home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / NIH Image 1.55 / Source / Macros1.p < prev    next >
Encoding:
Text File  |  1994-04-25  |  102.6 KB  |  4,873 lines  |  [TEXT/PJMM]

  1. unit Macros1;
  2. {Contains the recursive descent parser/interpreter}
  3. {for NIH Image's Pascal-like macro language.}
  4.  
  5. {References:}
  6. {  "Pascal User Manual and Report", Kathleen Jensen and Niklaus Wirth, Springer-Verlag}
  7. {  "Building Your Own C Interpreter", Dr. Dobb's Journal, August 1989}
  8.  
  9. interface
  10.  
  11.     uses
  12.         QuickDraw, Palettes, Picker, PrintTraps, Globals, Utilities, Graphics, Edit, {}
  13.         Analysis, Camera, File1, File2, Filters, Macros2, Stacks, Lut, Background, {}
  14.         User, Serial, PlugIns, Text, projection, math; {,UMacroDef, UMacroRun}
  15.  
  16.  
  17.     procedure RunMacro (nMacro: integer);
  18.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  19.     procedure CloseSerialPorts;
  20.  
  21.  
  22. implementation
  23.  
  24.     const
  25.         EndExpected = '"end" or ";" expected';
  26.         ThenExpected = '"then" expected';
  27.         DivideByZero = 'Divide by zero';
  28.         DoExpected = '"do" expected';
  29.         UntilExpected = '"until" expected';
  30.         RightParenExpected = '")" expected';
  31.         NoImageOpen = 'No Image open';
  32.         MaxArgs = 25;
  33.  
  34.     var
  35.         nSaves, ErrorPC, LineStartPC: integer;
  36.         DoOption: boolean;
  37.         SaveBackground, SavePicWidth, SavePicHeight: integer;
  38.         SaveMethod: rsMethodType;
  39.         SaveCreate, SaveInvertY, SaveScaleArithmetic, SaveScaleConvolutions: boolean;
  40.         SaveAngle, SaveH, SaveV: real;
  41.         MacroOpPending, StringsAllocated, InPhotoMode: boolean;
  42.         RoutinesCalled: set of CommandType;
  43.  
  44.  
  45.  
  46.     function GetExpression: extended;
  47.     forward;
  48.     procedure DoStatement;
  49.     forward;
  50.     procedure SkipStatement;
  51.     forward;
  52.     procedure DoFor;
  53.     forward;
  54.     procedure MacroError (str: str255);
  55.     forward;
  56.     function GetString: str255;
  57.     forward;
  58.     function GetInteger: LongInt;
  59.     forward;
  60.     procedure SkipIf;
  61.     forward;
  62.     procedure SkipPartialStatement;
  63.     forward;
  64.  
  65.  
  66. {$S MacroUtil}
  67. {Routines from here to the $S compiler directive go in the MacroUtil segment}
  68.  
  69.  
  70.     procedure PutTokenBack;
  71.     begin
  72.         if token <> DoneT then begin
  73.                 pc := SavePC;
  74.                 token := SaveToken;
  75.             end;
  76.     end;
  77.  
  78.  
  79.     procedure DeallocateStrings (first, last: integer);
  80.         var
  81.             i: integer;
  82.     begin
  83.         with MacrosP^ do begin
  84.                 for i := first to last do begin
  85.                         if Stack[i].StringH <> nil then begin
  86.                                 DisposHandle(handle(Stack[i].StringH));
  87.                                 Stack[i].StringH := nil;
  88.                             end;
  89.                     end;
  90.             end;
  91.     end;
  92.  
  93.  
  94.     procedure TrimString (var str: str255);
  95.     begin
  96.         if length(str) > 0 then begin
  97.                 while (length(str) > 1) and (str[1] = ' ') do
  98.                     delete(str, 1, 1);
  99.                 while (length(str) > 1) and ((str[length(str)] = ' ') or (str[length(str)] = ';')) do
  100.                     delete(str, length(str), 1);
  101.             end;
  102.     end;
  103.  
  104.  
  105.     procedure LookupVariable;
  106.         var
  107.             VarFound: boolean;
  108.             i: integer;
  109.     begin
  110.         with MacrosP^ do begin
  111.                 VarFound := false;
  112.                 i := TopOfStack + 1;
  113.                 repeat
  114.                     i := i - 1;
  115.                     VarFound := SymbolTableLoc = Stack[i].SymbolTableIndex
  116.                 until VarFound or (i = 1);
  117.                 if VarFound then
  118.                     with stack[i] do begin
  119.                             TokenValue := value;
  120.                             if vType <> StringVar then
  121.                                 token := Variable
  122.                             else begin
  123.                                     token := StringVariable;
  124.                                     if StringH <> nil then
  125.                                         TokenStr := StringH^^
  126.                                     else
  127.                                         TokenStr := 'Deallocated String';
  128.                                 end;
  129.                             TokenStackLoc := i;
  130.                         end;
  131.             end; {with}
  132.     end;
  133.  
  134.  
  135.     function FetchInteger: integer;
  136.         var
  137.             temp: integer;
  138.     begin
  139.         with macrosP^ do begin
  140.                 temp := ord(macros[pc]);
  141.                 pc := pc + 1;
  142.                 FetchInteger := bor(bsl(temp, 8), ord(macros[pc]));
  143.                 pc := pc + 1;
  144.             end;
  145.     end;
  146.  
  147.  
  148.     procedure LookupProcedure;
  149.     begin
  150.         with MacrosP^ do begin
  151.                 SymbolTableLoc := FetchInteger;
  152.                 with SymbolTable[SymbolTableLoc] do begin
  153.                         TokenLoc := loc;
  154.                         TokenSymbol := symbol;
  155.                     end;
  156.             end;
  157.     end;
  158.  
  159.  
  160.     function FetchReal: real;
  161.         var
  162.             temp: LongInt;
  163.     begin
  164.         with macrosP^ do begin
  165.                 temp := ord(macros[pc]);
  166.                 pc := pc + 1;
  167.                 temp := bor(bsl(temp, 8), ord(macros[pc]));
  168.                 pc := pc + 1;
  169.                 temp := bor(bsl(temp, 8), ord(macros[pc]));
  170.                 pc := pc + 1;
  171.                 temp := bor(bsl(temp, 8), ord(macros[pc]));
  172.                 pc := pc + 1;
  173.                 FetchReal := real(temp);
  174.             end;
  175.     end;
  176.  
  177.  
  178.     procedure GetToken;
  179.     begin
  180.         with MacrosP^ do begin
  181.                 if token = DoneT then
  182.                     exit(GetToken);
  183.                 SavePC := PC;
  184.                 SaveToken := token;
  185.                 token := TokenType(macros[pc]);
  186.                 while token = NewLineT do begin
  187.                         MacroLineNumber := MacroLineNumber + 1;
  188.                         pc := pc + 1;
  189.                         LineStartPC := pc;
  190.                         if pc > EndMacros then begin
  191.                                 Token := DoneT;
  192.                                 exit(GetToken);
  193.                             end;
  194.                         SavePC := PC;
  195.                         SaveToken := token;
  196.                         token := TokenType(macros[pc]);
  197.                     end;
  198.                 pc := pc + 1;
  199.                 if pc > EndMacros then begin
  200.                         Token := DoneT;
  201.                         exit(GetToken);
  202.                     end;
  203.                 case token of
  204.                     CommandT, FunctionT, StringFunctionT, ArrayT, UserCommandT, UserFuncT, UserStrFuncT: 
  205.                         MacroCommand := CommandType(FetchInteger);
  206.                     Identifier:  begin
  207.                             SymbolTableLoc := FetchInteger;
  208.                             if TopOfStack > 0 then
  209.                                 LookupVariable;
  210.                         end;
  211.                     ProcedureT: 
  212.                         LookupProcedure;
  213.                     NumericLiteral: 
  214.                         TokenValue := FetchReal;
  215.                     StringLiteral:  begin
  216.                             TokenStr := '';
  217.                             while macros[pc] <> chr(0) do begin
  218.                                     TokenStr := concat(TokenStr, macros[pc]);
  219.                                     pc := pc + 1;
  220.                                 end;
  221.                             pc := pc + 1;
  222.                         end;
  223.                 end; {case}
  224.             end; {with}
  225.     end;
  226.  
  227.  
  228.     procedure GetMacroName;
  229.         var
  230.             i, len: integer;
  231.     begin
  232.         with MacrosP^ do begin
  233.                 pc := PCStart;
  234.                 repeat
  235.                     pc := pc - 1;
  236.                     if pc < 0 then
  237.                         exit(GetMacroName);
  238.                 until macros[pc] = chr(ord(MacroT));
  239.                 GetToken; {MacroT}
  240.                 GetToken; {Macro name}
  241.                 if Token = StringLiteral then begin
  242.                         len := length(TokenStr);
  243.                         if len > SymbolSize then
  244.                             len := SymbolSize;
  245.                         for i := 1 to len do
  246.                             MacroOrProcName[i] := TokenStr[i];
  247.                     end;
  248.             end;
  249.     end;
  250.  
  251.  
  252.     procedure ConvertTokenToString (t: TokenType; var str: str255);
  253.         var
  254.             i, j, len: integer;
  255.     begin
  256.         with MacrosP^ do
  257.             case token of
  258.                 semicolon: 
  259.                     str := ';';
  260.                 comma: 
  261.                     str := ',';
  262.                 colon: 
  263.                     str := ':';
  264.                 LeftParen: 
  265.                     str := '(';
  266.                 RightParen: 
  267.                     str := ')';
  268.                 LeftBracket: 
  269.                     str := '[';
  270.                 RightBracket: 
  271.                     str := ']';
  272.                 PlusOp: 
  273.                     str := '+';
  274.                 MinusOp: 
  275.                     str := '-';
  276.                 MulOp: 
  277.                     str := '*';
  278.                 DivOp: 
  279.                     str := '/';
  280.                 eqOp: 
  281.                     str := '=';
  282.                 ltOp: 
  283.                     str := '<';
  284.                 gtOp: 
  285.                     str := '>';
  286.                 neOp: 
  287.                     str := '<>';
  288.                 leOp: 
  289.                     str := '<=';
  290.                 geOp: 
  291.                     str := '>=';
  292.                 orOp: 
  293.                     str := 'or';
  294.                 IntDivOp: 
  295.                     str := 'div';
  296.                 modOp: 
  297.                     str := 'mod';
  298.                 andOp: 
  299.                     str := 'and';
  300.                 NotOp: 
  301.                     str := 'not';
  302.                 AssignOp: 
  303.                     str := ':=';
  304.                 Identifier, Variable, StringVariable, ProcIdT:  begin
  305.                         for i := 1 to SymbolSize do
  306.                             str := concat(str, SymbolTable[SymbolTableLoc].symbol[i]);
  307.                         TrimString(str);
  308.                     end;
  309.                 NumericLiteral:  begin
  310.                         if trunc(TokenValue) = TokenValue then
  311.                             RealToString(TokenValue, 1, 0, str)
  312.                         else
  313.                             RealToString(TokenValue, 1, 1, str);
  314.                     end;
  315.                 StringLiteral: 
  316.                     str := concat('''', TokenStr, '''');
  317.                 CommandT, FunctionT, StringFunctionT, ArrayT, UserCommandT, UserFuncT, UserStrFuncT: 
  318.                     for i := 1 to nSymbols do begin
  319.                             with SymbolTable[i] do
  320.                                 if (tType = token) and (MacroCommand = cType) then begin
  321.                                         for j := 1 to SymbolSize do
  322.                                             str := concat(str, symbol[j]);
  323.                                         TrimString(str);
  324.                                     end;
  325.                         end; {for}
  326.                 otherwise
  327.                     for i := 1 to nSymbols do begin
  328.                             with SymbolTable[i] do
  329.                                 if tType = token then begin
  330.                                         for j := 1 to SymbolSize do
  331.                                             str := concat(str, symbol[j]);
  332.                                         TrimString(str);
  333.                                     end;
  334.                         end; {for}
  335.             end; {case}
  336.     end;
  337.  
  338.  
  339.     procedure GetErrorLine (var ErrorLine: str255);
  340.         var
  341.             str: str255;
  342.     begin
  343.         with MacrosP^ do begin
  344.                 pc := LineStartPC;
  345.                 ErrorLine := '';
  346.                 repeat
  347.                     str := '';
  348.                     if macros[pc] = chr(ord(NewLineT)) then
  349.                         leave;
  350.                     GetToken;
  351.                     ConvertTokenToString(token, str);
  352.                     if SavePC = ErrorPC then
  353.                         str := concat('«', str, '»');
  354.                     ErrorLine := concat(ErrorLine, ' ', str);
  355.                 until token = DoneT;
  356.             end;
  357.     end;
  358.  
  359.  
  360.     procedure GetLineNumber;
  361.     begin
  362.         pc := PCStart;
  363.         MacroLineNumber := 1;
  364.         while (pc <= errorpc) and (token <> DoneT) do
  365.             GetToken;
  366.     end;
  367.  
  368.  
  369.     procedure MacroError (str: str255);
  370.   {Report run-time errors}
  371.         var
  372.             name, ErrorLine: str255;
  373.             i, count, ignore: integer;
  374.     begin
  375.         with MacrosP^ do begin
  376.                 if token = DoneT then
  377.                     exit(MacroError);
  378.                 if TopOfStack > 0 then
  379.                     DeAllocateStrings(nGlobals + 1, TopOfStack);
  380.                 ErrorPC := SavePC;
  381.                 if MacroOrProcName = BlankSymbol then
  382.                     GetMacroName;
  383.                 if MacroOrProcName[SymbolSize] <> ' ' then
  384.                     MacroOrProcName[SymbolSize] := '…';
  385.                 name := MacroOrProcName;
  386.                 TrimString(name);
  387.                 GetLineNumber;
  388.                 GetErrorLine(ErrorLine);
  389.                 InitCursor;
  390.                 ParamText(str, long2str(MacroLineNumber), Name, ErrorLine);
  391.                 Ignore := Alert(900, nil);
  392.                 Token := DoneT;
  393.             end; {with}
  394.     end;
  395.  
  396.  
  397.     procedure DoDeclaration;
  398.         var
  399.             SaveStackLoc, StackLoc: integer;
  400.     begin
  401.         SaveStackLoc := TopOfStack;
  402.         while (token = Identifier) or (token = variable) or (token = comma) or (token = StringVariable) do begin
  403.                 if token = StringVariable then begin
  404.                         MacroError('Variable previously defined');
  405.                         exit(DoDeclaration);
  406.                     end;
  407.                 if TopOfStack >= MaxMacroStackSize then begin
  408.                         MacroError(StackOverflow);
  409.                         exit(DoDeclaration);
  410.                     end;
  411.                 TopOfStack := TopOfStack + 1;
  412.                 with MacrosP^.stack[TopOfStack] do begin
  413.                         SymbolTableIndex := SymbolTableLoc;
  414.                         value := 0.0;
  415.                         StringH := nil;
  416.                     end;
  417.                 GetToken;
  418.                 if token = comma then
  419.                     GetToken;
  420.             end; {while}
  421.         if (token = FunctionT) or (token = StringFunctionT) or (token = CommandT) or (token = ArrayT) then
  422.             MacroError('Predefined identifier');
  423.         if token <> colon then
  424.             MacroError('":" expected');
  425.         GetToken;
  426.         if (token <> IntegerT) and (token <> RealT) and (token <> BooleanT) and (token <> StringT) then
  427.             MacroError('"integer", "real", "boolean" or "string" expected');
  428.         for StackLoc := SaveStackLoc + 1 to TopOfStack do
  429.             with macrosP^.stack[StackLoc] do
  430.                 case token of
  431.                     IntegerT: 
  432.                         vType := IntVar;
  433.                     RealT: 
  434.                         vType := RealVar;
  435.                     BooleanT: 
  436.                         vType := BooleanVar;
  437.                     StringT:  begin
  438.                             StringsAllocated := true;
  439.                             vType := StringVar;
  440.                             StringH := str255H(NewHandle(SizeOf(str255)));
  441.                             if StringH = nil then begin
  442.                                     MacroError('Out of memory');
  443.                                     Token := DoneT
  444.                                 end
  445.                             else
  446.                                 StringH^^ := 'Local String';
  447.                         end;
  448.                     otherwise
  449.                 end;
  450.         GetToken;
  451.         if Token = SemiColon then
  452.             GetToken;
  453.     end;
  454.  
  455.  
  456.     procedure GetLeftParen;
  457.     begin
  458.         GetToken;
  459.         if token <> LeftParen then
  460.             MacroError('"(" expected');
  461.     end;
  462.  
  463.  
  464.     procedure GetRightParen;
  465.     begin
  466.         GetToken;
  467.         if token <> RightParen then
  468.             MacroError(RightParenExpected);
  469.     end;
  470.  
  471.  
  472.     procedure GetComma;
  473.     begin
  474.         GetToken;
  475.         if token <> comma then
  476.             MacroError('"," expected');
  477.     end;
  478.  
  479.  
  480.     procedure GetArguments (var str: str255);
  481.         var
  482.             width, fwidth: integer;
  483.             i: LongInt;
  484.             isExpression, ZeroFill, noArgs: boolean;
  485.             n: extended;
  486.             str2: str255;
  487.     begin
  488.         if MacroCommand = WritelnC then begin {Check for Writeln with no arguments}
  489.                 GetToken;
  490.                 noArgs := token <> LeftParen;
  491.                 PutTokenBack;
  492.                 if NoArgs then begin
  493.                         str := '';
  494.                         exit(GetArguments);
  495.                     end;
  496.             end;
  497.         ZeroFill := not (MacroCommand in [DrawTextC, WriteC, WritelnC, PutMsgC, ShowMsgC, PutSerialC, ConcatC]);
  498.         width := 4;
  499.         fwidth := 0;
  500.         str := '';
  501.         GetLeftParen;
  502.         GetToken;
  503.         repeat
  504.             isExpression := token in [Variable, NumericLiteral, FunctionT, UserFuncT, TrueT, FalseT, ArrayT, MinusOp, LeftParen];
  505.             PutTokenBack;
  506.             if isExpression then
  507.                 n := GetExpression
  508.             else
  509.                 str2 := GetString;
  510.             GetToken;
  511.             if token = colon then begin
  512.                     width := GetInteger;
  513.                     if width < 0 then
  514.                         width := 0;
  515.                     if width > 100 then
  516.                         width := 100;
  517.                     GetToken;
  518.                     if token = colon then begin
  519.                             fwidth := GetInteger;
  520.                             if fwidth < 0 then
  521.                                 width := 0;
  522.                             if fwidth > 12 then
  523.                                 width := 12;
  524.                             GetToken;
  525.                         end;
  526.                 end;
  527.             if token = comma then
  528.                 GetToken;
  529.             if isExpression then begin
  530.                     RealToString(n, width, fwidth, str2);
  531.                     if ZeroFill and (n >= 0) then
  532.                         for i := 1 to width do
  533.                             if str2[i] = ' ' then
  534.                                 str2[i] := '0';
  535.                 end;
  536.             str := concat(str, str2);
  537.         until (token = RightParen) or (token = DoneT);
  538.     end;
  539.  
  540.  
  541.     procedure DoUserToken;
  542.     begin
  543.         MacroError('UMX package not installed');
  544.     end;
  545.  
  546.  
  547.     function DoGetString: str255; {(prompt,default:str255)}
  548.         const
  549.             StringID = 3;
  550.         var
  551.             prompt, default: str255;
  552.             Canceled: boolean;
  553.             mylog: DialogPtr;
  554.             item: integer;
  555.     begin
  556.         GetLeftParen;
  557.         prompt := GetString;
  558.         GetToken;
  559.         if token = Comma then
  560.             default := GetString
  561.         else begin
  562.                 default := '';
  563.                 PutTokenBack
  564.             end;
  565.         GetRightParen;
  566.         if Token <> DoneT then begin
  567.                 InitCursor;
  568.                 ParamText(prompt, '', '', '');
  569.                 mylog := GetNewDialog(170, nil, pointer(-1));
  570.                 SetDString(MyLog, StringID, default);
  571.                 SelIText(MyLog, StringID, 0, 32767);
  572.                 OutlineButton(MyLog, ok, 16);
  573.                 repeat
  574.                     ModalDialog(nil, item);
  575.                 until (item = ok) or (item = cancel);
  576.                 if item = ok then
  577.                     DoGetString := GetDString(MyLog, StringID)
  578.                 else begin
  579.                         DoGetString := 'cancel';
  580.                         token := DoneT;
  581.                     end;
  582.                 DisposDialog(mylog);
  583.             end;
  584.     end;
  585.  
  586.  
  587.     function GetSerial: str255;
  588.         var
  589.             count: LongInt;
  590.             buffer: packed array[1..100] of char;
  591.             err: OSErr;
  592.     begin
  593.         if SerialBufferP = nil then begin
  594.                 MacroError('Serial port not open');
  595.                 exit(GetSerial);
  596.             end;
  597.         Err := SerGetBuf(SerialIn, count);
  598.         if count > 0 then begin
  599.                 count := 1;
  600.                 Err := FSRead(SerialIn, count, @buffer);
  601.                 GetSerial := buffer[1]
  602.             end
  603.         else
  604.             GetSerial := '';
  605.     end;
  606.  
  607.  
  608.     procedure RangeCheck (i: LongInt);
  609.     begin
  610.         if (i < 0) or (i > 255) then
  611.             MacroError('Argument is less than 0 or greater than 255');
  612.     end;
  613.  
  614.  
  615.     function DoChr: str255;
  616.         var
  617.             i: LongInt;
  618.     begin
  619.         GetLeftParen;
  620.         i := GetInteger;
  621.         GetRightParen;
  622.         RangeCheck(i);
  623.         if Token <> DoneT then
  624.             DoChr := chr(i);
  625.     end;
  626.  
  627.  
  628.     function GetWindowTitle: str255;
  629.         var
  630.             wPeek: WindowPeek;
  631.     begin
  632.         wPeek := WindowPeek(FrontWindow);
  633.         if wPeek = nil then begin
  634.                 GetWindowTitle := '';
  635.                 exit(GetWindowTitle);
  636.             end;
  637.         if wPeek^.WindowKind = PicKind then
  638.             GetWindowTitle := Info^.title
  639.         else
  640.             GetWindowTitle := wPeek^.TitleHandle^^;
  641.     end;
  642.  
  643.  
  644.     function DoStringFunction: str255;
  645.         var
  646.             str: str255;
  647.     begin
  648.         case MacroCommand of
  649.             GetStringC: 
  650.                 DoStringFunction := DoGetString;
  651.             ChrC: 
  652.                 DoStringFunction := DoChr;
  653.             GetSerialC: 
  654.                 DoStringFunction := GetSerial;
  655.             ConcatC:  begin
  656.                     GetArguments(str);
  657.                     DoStringFunction := str;
  658.                 end;
  659.             WindowTitleC: 
  660.                 DoStringFunction := GetWindowTitle;
  661.             otherwise
  662.                 MacroError('"GetString ", "GetSerial" or "chr" expected');
  663.         end;
  664.     end;
  665.  
  666.  
  667.     function GetString: str255;
  668.     begin
  669.         GetToken;
  670.         if token = StringFunctionT then
  671.             GetString := DoStringFunction
  672.         else if token = UserStrFuncT then begin
  673.                 DoUserToken; {result in TokenStr}
  674.                 GetString := TokenStr;
  675.             end
  676.         else if (token = StringLiteral) or (token = StringVariable) then
  677.             GetString := TokenStr
  678.         else begin
  679.                 MacroError('String expected');
  680.                 GetString := '';
  681.             end;
  682.     end;
  683.  
  684.  
  685.     function GetInteger: LongInt;
  686.         var
  687.             n: LongInt;
  688.             r: extended;
  689.     begin
  690.         r := GetExpression;
  691.         if token = DoneT then begin
  692.                 GetInteger := 0;
  693.                 exit(GetInteger);
  694.             end;
  695.         GetInteger := round(r);
  696.     end;
  697.  
  698.  
  699.     procedure CheckBoolean (b: extended);
  700.     begin
  701.         if (b <> ord(true)) and (b <> ord(false)) then
  702.             MacroError('Boolean expression expected');
  703.     end;
  704.  
  705.  
  706.     function GetBoolean: boolean;
  707.         var
  708.             value: extended;
  709.     begin
  710.         value := GetExpression;
  711.         CheckBoolean(value);
  712.         GetBoolean := value = ord(true);
  713.     end;
  714.  
  715.  
  716.     function GetBooleanArg: boolean;
  717.     begin
  718.         GetLeftParen;
  719.         GetBooleanArg := GetBoolean;
  720.         GetRightParen;
  721.     end;
  722.  
  723.  
  724.     function GetStringArg: str255;
  725.     begin
  726.         GetLeftParen;
  727.         GetStringArg := GetString;
  728.         GetRightParen;
  729.     end;
  730.  
  731.  
  732.     procedure DoConvolve;
  733.         var
  734.             err: OSErr;
  735.             f: integer;
  736.             FileFound: boolean;
  737.             fname: str255;
  738.     begin
  739.         fname := GetStringArg;
  740.         if token <> DoneT then begin
  741.                 if (fname = '') and (CurrentWindow = TextKind) then begin
  742.                         ConvolveUsingText;
  743.                         exit(DoConvolve);
  744.                     end;
  745.                 err := fsopen(fname, KernelsRefNum, f);
  746.                 FileFound := err = NoErr;
  747.                 err := fsclose(f);
  748.                 if FileFound then
  749.                     convolve(fname, KernelsRefNum)
  750.                 else
  751.                     convolve('', 0);
  752.             end;
  753.     end;
  754.  
  755.  
  756.     function GetNumber: extended; {(prompt:str255; default:extended)}
  757.         var
  758.             prompt: str255;
  759.             default, n: extended;
  760.             Canceled: boolean;
  761.     begin
  762.         GetLeftParen;
  763.         prompt := GetString;
  764.         GetComma;
  765.         default := GetExpression;
  766.         GetRightParen;
  767.         n := 0.0;
  768.         if Token <> DoneT then begin
  769.                 n := GetReal(prompt, default, Canceled);
  770.                 if Canceled then begin
  771.                         n := default;
  772.                         token := DoneT;
  773.                     end;
  774.             end;
  775.         GetNumber := n;
  776.     end;
  777.  
  778.  
  779.     function DoGetPixel: extended; {(hloc,vloc:integer)}
  780.         var
  781.             hloc, vloc: integer;
  782.     begin
  783.         GetLeftParen;
  784.         hloc := GetInteger;
  785.         GetComma;
  786.         vloc := GetInteger;
  787.         GetRightParen;
  788.         if (Token <> DoneT) and (info <> NoInfo) then
  789.             DoGetPixel := MyGetPixel(hloc, vloc)
  790.         else
  791.             DoGetPixel := 0.0;
  792.     end;
  793.  
  794.  
  795.     function DoFunction (c: CommandType): extended;
  796.         var
  797.             n: extended;
  798.             SaveCommand: CommandType;
  799.     begin
  800.         SaveCommand := MacroCommand;
  801.         GetLeftParen;
  802.         n := GetExpression;
  803.         GetRightParen;
  804.         if Token <> DoneT then
  805.             case SaveCommand of
  806.                 truncC: 
  807.                     DoFunction := trunc(n);
  808.                 roundC: 
  809.                     DoFunction := round(n);
  810.                 oddC: 
  811.                     if odd(trunc(n)) then
  812.                         DoFunction := ord(true)
  813.                     else
  814.                         DoFunction := ord(false);
  815.                 absC: 
  816.                     DoFunction := abs(n);
  817.                 sqrtC: 
  818.                     if n < 0.0 then
  819.                         MacroError('Sqrt Error')
  820.                     else
  821.                         DoFunction := sqrt(n);
  822.                 sqrC: 
  823.                     DoFunction := sqr(n);
  824.                 sinC: 
  825.                     DoFunction := sin(n);
  826.                 cosC: 
  827.                     DoFunction := cos(n);
  828.                 expC: 
  829.                     DoFunction := exp(n);
  830.                 lnC: 
  831.                     if n <= 0.0 then
  832.                         MacroError('Log Error')
  833.                     else
  834.                         DoFunction := ln(n);
  835.                 arctanC: 
  836.                     DoFunction := arctan(n);
  837.             end
  838.         else
  839.             DoFunction := 0.0;
  840.     end;
  841.  
  842.  
  843.     function CalibrateValue: extended;
  844.         var
  845.             i: integer;
  846.     begin
  847.         GetLeftParen;
  848.         i := GetInteger;
  849.         GetRightParen;
  850.         RangeCheck(i);
  851.         if Token <> DoneT then begin
  852.                 CalibrateValue := cvalue[i];
  853.             end;
  854.     end;
  855.  
  856.  
  857.     function DoOrd: extended;
  858.         var
  859.             str: str255;
  860.     begin
  861.         GetLeftParen;
  862.         str := GetString;
  863.         GetRightParen;
  864.         if Token <> DoneT then begin
  865.                 if length(str) >= 1 then
  866.                     DoOrd := ord(str[1])
  867.                 else
  868.                     DoOrd := -1;
  869.             end;
  870.     end;
  871.  
  872.  
  873.     function DoStringToNum: extended;
  874.         var
  875.             str: str255;
  876.             n: extended;
  877.     begin
  878.         GetLeftParen;
  879.         str := GetString;
  880.         GetRightParen;
  881.         if Token <> DoneT then begin
  882.                 n := StringToReal(str);
  883.                 if n = BadReal then
  884.                     DoStringToNum := 0.0
  885.                 else
  886.                     DoStringToNum := n;
  887.             end;
  888.     end;
  889.  
  890.  
  891.     function DoLogicalFunction (c: CommandType): extended;
  892.         var
  893.             n1, n2: LongInt;
  894.     begin
  895.         GetLeftParen;
  896.         n1 := GetInteger;
  897.         GetComma;
  898.         n2 := GetInteger;
  899.         GetRightParen;
  900.         if Token <> DoneT then begin
  901.                 if c = BitAndC then
  902.                     DoLogicalFunction := band(n1, n2)
  903.                 else
  904.                     DoLogicalFunction := bor(n1, n2)
  905.             end;
  906.     end;
  907.  
  908.  
  909.     function PidExists: boolean; {(pid:integer)}
  910.         var
  911.             pid, i: integer;
  912.     begin
  913.         GetLeftParen;
  914.         pid := GetInteger;
  915.         GetRightParen;
  916.         if Token <> DoneT then begin
  917.                 PidExists := false;
  918.                 for i := 1 to nPics do
  919.                     if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = pid then begin
  920.                             PidExists := true;
  921.                             leave;
  922.                         end;
  923.             end;
  924.     end;
  925.  
  926.  
  927.     function DoPos: integer;
  928.         var
  929.             substr, str: str255;
  930.     begin
  931.         GetLeftParen;
  932.         substr := GetString;
  933.         GetComma;
  934.         str := GetString;
  935.         GetRightParen;
  936.         if Token <> DoneT then
  937.             DoPos := pos(substr, str);
  938.     end;
  939.  
  940.  
  941.     function DoLength: integer;
  942.         var
  943.             str: str255;
  944.     begin
  945.         GetLeftParen;
  946.         str := GetString;
  947.         GetRightParen;
  948.         if Token <> DoneT then
  949.             DoLength := length(str);
  950.     end;
  951.  
  952.  
  953.     function ExecuteFunction: extended;
  954.     begin
  955.         case MacroCommand of
  956.             TruncC, RoundC, oddC, absC, sqrtC, sqrC, sinC, cosC, expC, lnC, arctanC: 
  957.                 ExecuteFunction := DoFunction(MacroCommand);
  958.             GetNumC: 
  959.                 ExecuteFunction := GetNumber;
  960.             RandomC: 
  961.                 ExecuteFunction := (random + 32767.0) / 65534.0;
  962.             GetPixelC: 
  963.                 ExecuteFunction := DoGetPixel;
  964.             ButtonC:  begin
  965.                     ExecuteFunction := ord(Button);
  966.                     FlushEvents(EveryEvent, 0);
  967.                 end;
  968.             nPicsC: 
  969.                 ExecuteFunction := nPics;
  970.             PicNumC: 
  971.                 ExecuteFunction := info^.PicNum;
  972.             PidNumC: 
  973.                 ExecuteFunction := info^.PidNum;
  974.             PidExistsC: 
  975.                 ExecuteFunction := ord(PidExists);
  976.             SameSizeC: 
  977.                 ExecuteFunction := ord(AllSameSize);
  978.             cValueC: 
  979.                 ExecuteFunction := CalibrateValue;
  980.             CalibratedC: 
  981.                 ExecuteFunction := ord(info^.DensityCalibrated);
  982.             rCountC: 
  983.                 ExecuteFunction := mCount;
  984.             GetSliceC: 
  985.                 with info^ do
  986.                     if StackInfo = nil then
  987.                         ExecuteFunction := 0
  988.                     else
  989.                         ExecuteFunction := Info^.StackInfo^.CurrentSlice;
  990.             nSlicesC: 
  991.                 with info^ do
  992.                     if StackInfo = nil then
  993.                         ExecuteFunction := 0
  994.                     else
  995.                         ExecuteFunction := Info^.StackInfo^.nSlices;
  996.             GetSpacingC: 
  997.                 with info^ do
  998.                     if StackInfo = nil then
  999.                         MacroError('No stack')
  1000.                     else
  1001.                         ExecuteFunction := Info^.StackInfo^.SliceSpacing;
  1002.             nCoordinatesC: 
  1003.                 ExecuteFunction := nCoordinates;
  1004.             OrdC: 
  1005.                 ExecuteFunction := DoOrd;
  1006.             TickCountC: 
  1007.                 ExecuteFunction := TickCount;
  1008.             StringToNumC: 
  1009.                 ExecuteFunction := DoStringToNum;
  1010.             UndoSizeC: 
  1011.                 ExecuteFunction := UndoBufSize;
  1012.             BitAndC, BitOrC: 
  1013.                 ExecuteFunction := DoLogicalFunction(MacroCommand);
  1014.             PosC: 
  1015.                 ExecuteFunction := DoPos;
  1016.             LengthC: 
  1017.                 ExecuteFunction := DoLength;
  1018.         end; {case}
  1019.     end;
  1020.  
  1021.  
  1022.     procedure CheckIndex (index: LongInt; min, max: extended);
  1023.     begin
  1024.         if (index < min) or (index > max) then
  1025.             MacroError('Array index out of range');
  1026.     end;
  1027.  
  1028.  
  1029.     function GetArrayValue: extended;
  1030.         var
  1031.             SaveCommand: CommandType;
  1032.             Index: LongInt;
  1033.             xcoord, ycoord: integer;
  1034.     begin
  1035.         SaveCommand := MacroCommand;
  1036.         GetToken;
  1037.         if token <> LeftBracket then
  1038.             MacroError('"[" expected');
  1039.         Index := GetInteger;
  1040.         GetToken;
  1041.         if token <> RightBracket then
  1042.             MacroError('"]" expected');
  1043.         case SaveCommand of
  1044.             HistogramC:  begin
  1045.                     CheckIndex(Index, 0, 255);
  1046.                     GetArrayValue := histogram[Index];
  1047.                 end;
  1048.             rAreaC:  begin
  1049.                     CheckIndex(Index, 1, MaxMeasurements);
  1050.                     GetArrayValue := mArea^[Index];
  1051.                 end;
  1052.             rMeanC:  begin
  1053.                     CheckIndex(Index, 1, MaxMeasurements);
  1054.                     GetArrayValue := mean^[Index];
  1055.                 end;
  1056.             rStdDevC:  begin
  1057.                     CheckIndex(Index, 1, MaxMeasurements);
  1058.                     GetArrayValue := sd^[Index];
  1059.                 end;
  1060.             rXC:  begin
  1061.                     CheckIndex(Index, 1, MaxMeasurements);
  1062.                     GetArrayValue := xcenter^[Index];
  1063.                 end;
  1064.             rYC:  begin
  1065.                     CheckIndex(Index, 1, MaxMeasurements);
  1066.                     GetArrayValue := ycenter^[Index];
  1067.                 end;
  1068.             rLengthC:  begin
  1069.                     CheckIndex(Index, 1, MaxMeasurements);
  1070.                     GetArrayValue := pLength^[Index];
  1071.                 end;
  1072.             rMinC:  begin
  1073.                     CheckIndex(Index, 1, MaxMeasurements);
  1074.                     GetArrayValue := mMin^[Index];
  1075.                 end;
  1076.             rMaxC:  begin
  1077.                     CheckIndex(Index, 1, MaxMeasurements);
  1078.                     GetArrayValue := mMax^[Index];
  1079.                 end;
  1080.             rMajorC:  begin
  1081.                     CheckIndex(Index, 1, MaxMeasurements);
  1082.                     GetArrayValue := MajorAxis^[Index];
  1083.                 end;
  1084.             rMinorC:  begin
  1085.                     CheckIndex(Index, 1, MaxMeasurements);
  1086.                     GetArrayValue := MinorAxis^[Index];
  1087.                 end;
  1088.             rAngleC:  begin
  1089.                     CheckIndex(Index, 1, MaxMeasurements);
  1090.                     GetArrayValue := orientation^[Index];
  1091.                 end;
  1092.             rUser1C:  begin
  1093.                     CheckIndex(Index, 1, MaxMeasurements);
  1094.                     GetArrayValue := User1^[Index];
  1095.                 end;
  1096.             rUser2C:  begin
  1097.                     CheckIndex(Index, 1, MaxMeasurements);
  1098.                     GetArrayValue := User2^[Index];
  1099.                 end;
  1100.             RedLutC, GreenLutC, BlueLutC: 
  1101.                 if OptionKeyDown then begin
  1102.                         CheckIndex(Index, 0, 255);
  1103.                         if Token <> DoneT then
  1104.                             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[index].rgb do
  1105.                                 case SaveCommand of
  1106.                                     RedLutC: 
  1107.                                         GetArrayValue := band(bsr(red, 8), 255);
  1108.                                     GreenLutC: 
  1109.                                         GetArrayValue := band(bsr(green, 8), 255);
  1110.                                     BlueLutC: 
  1111.                                         GetArrayValue := band(bsr(blue, 8), 255);
  1112.                                 end; {case}
  1113.                     end
  1114.                 else begin
  1115.                         CheckIndex(Index, 0, 255);
  1116.                         if Token <> DoneT then
  1117.                             with osGDevice^^.gdPMap^^.pmTable^^.ctTable[index].rgb do
  1118.                                 case SaveCommand of
  1119.                                     RedLutC: 
  1120.                                         GetArrayValue := band(bsr(red, 8), 255);
  1121.                                     GreenLutC: 
  1122.                                         GetArrayValue := band(bsr(green, 8), 255);
  1123.                                     BlueLutC: 
  1124.                                         GetArrayValue := band(bsr(blue, 8), 255);
  1125.                                 end; {case}
  1126.                     end;
  1127.             BufferC:  begin
  1128.                     CheckIndex(Index, 0, MaxLine - 1);
  1129.                     if Token <> DoneT then
  1130.                         GetArrayValue := MacrosP^.aLine[index];
  1131.                 end;
  1132.             PlotDataC:  begin
  1133.                     CheckIndex(Index, 0, MaxLine - 1);
  1134.                     if Token <> DoneT then
  1135.                         GetArrayValue := PlotData^[index];
  1136.                 end;
  1137.             xCoordinatesC:  begin
  1138.                     CheckIndex(Index, 1, MaxCoordinates);
  1139.                     if Token <> DoneT then
  1140.                         with info^ do begin
  1141.                                 xcoord := xCoordinates^[index];
  1142.                                 if SpatiallyCalibrated then
  1143.                                     GetArrayValue := xcoord / xSpatialScale
  1144.                                 else
  1145.                                     GetArrayValue := xcoord
  1146.                             end;
  1147.                 end;
  1148.             yCoordinatesC:  begin
  1149.                     CheckIndex(Index, 1, MaxCoordinates);
  1150.                     if Token <> DoneT then
  1151.                         with info^ do begin
  1152.                                 ycoord := yCoordinates^[index];
  1153.                                 if InvertYCoordinates and (Info <> NoInfo) then
  1154.                                     ycoord := Info^.PicRect.bottom - ycoord - 1;
  1155.                                 if SpatiallyCalibrated then
  1156.                                     GetArrayValue := ycoord / ySpatialScale
  1157.                                 else
  1158.                                     GetArrayValue := ycoord
  1159.                             end;
  1160.                 end;
  1161.             ScionC:  begin
  1162.                     if framegrabber <> ScionLG3 then
  1163.                         MacroError('No Scion LG-3');
  1164.                     if Token <> DoneT then
  1165.                         CheckIndex(Index, 1, 4);
  1166.                     if Token <> DoneT then
  1167.                         case index of
  1168.                             1: 
  1169.                                 GetArrayValue := LG3DacA;
  1170.                             2: 
  1171.                                 GetArrayValue := LG3DacB;
  1172.                             3: 
  1173.                                 GetArrayValue := ControlReg^;
  1174.                             4: 
  1175.                                 GetArrayValue := LG3DataOut;
  1176.                         end;
  1177.                 end;
  1178.         end; {case}
  1179.     end;
  1180.  
  1181.  
  1182.     function GetStringValue: extended;
  1183.  {Convert string to a base 102 number so we can do comparisons.}
  1184.         const
  1185.             base = 102;
  1186.         var
  1187.             i, j: integer;
  1188.             v, k: extended;
  1189.     begin
  1190.         MakeLowerCase(TokenStr);
  1191.         k := 1;
  1192.         v := 0.0;
  1193.         for i := 1 to length(TokenStr) do begin
  1194.                 j := ord(TokenStr[i]);
  1195.                 if j > 127 then
  1196.                     j := 127;
  1197.                 if j >= 91 then
  1198.                     j := j - 26;
  1199.                 v := v + j * k;
  1200.                 k := k * base;
  1201.             end;
  1202.         GetStringValue := v;
  1203.     end;
  1204.  
  1205.  
  1206.     function GetValue: extended;
  1207.     begin
  1208.         case token of
  1209.             Variable, NumericLiteral: 
  1210.                 GetValue := TokenValue;
  1211.             FunctionT: 
  1212.                 GetValue := ExecuteFunction;
  1213.             StringFunctionT:  begin
  1214.                     TokenStr := DoStringFunction;
  1215.                     GetValue := GetStringValue;
  1216.                 end;
  1217.             UserFuncT:  begin
  1218.                     DoUserToken;{output in TokenValue}
  1219.                     GetValue := TokenValue;
  1220.                 end;
  1221.             UserStrFuncT:  begin
  1222.                     DoUserToken; {output in TokenStr}
  1223.                     GetValue := GetStringValue;
  1224.                 end;
  1225.             TrueT: 
  1226.                 GetValue := ord(true);
  1227.             FalseT: 
  1228.                 GetValue := ord(false);
  1229.             ArrayT: 
  1230.                 GetValue := GetArrayValue;
  1231.             StringVariable, StringLiteral: 
  1232.                 GetValue := GetStringValue;
  1233.             otherwise begin
  1234.                     MacroError('Number expected');
  1235.                     GetValue := 0.0;
  1236.                     exit(GetValue);
  1237.                 end;
  1238.         end; {case}
  1239.     end;
  1240.  
  1241.  
  1242.     function GetFactor: extended;
  1243.         var
  1244.             fValue: extended;
  1245.             isUnaryMinus, isNot: boolean;
  1246.     begin
  1247.         GetToken;
  1248.         isUnaryMinus := token = MinusOp;
  1249.         isNot := token = NotOp;
  1250.         if isUnaryMinus or isNot then
  1251.             GetToken;
  1252.         case token of
  1253.             Variable, NumericLiteral, FunctionT, StringFunctionT, UserFuncT, {}
  1254.             UserStrFuncT, TrueT, FalseT, ArrayT, StringVariable, StringLiteral: 
  1255.                 fValue := GetValue;
  1256.             LeftParen:  begin
  1257.                     fValue := GetExpression;
  1258.                     GetRightParen;
  1259.                 end;
  1260.             otherwise begin
  1261.                     macroError('Undefined identifier');
  1262.                     fvalue := 0.0
  1263.                 end;
  1264.         end;
  1265.         GetToken;
  1266.         if isUnaryMinus then
  1267.             fValue := -fValue;
  1268.         if isNot then
  1269.             if fValue = ord(true) then
  1270.                 fValue := ord(false)
  1271.             else
  1272.                 fValue := ord(true);
  1273.         GetFactor := fValue;
  1274.     end;
  1275.  
  1276.  
  1277.     function GetTerm: extended;
  1278.         var
  1279.             tValue, fValue: extended;
  1280.             op: TokenType;
  1281.     begin
  1282.         tValue := GetFactor;
  1283.         while token in [MulOp, IntDivOp, ModOp, DivOp, AndOp] do begin
  1284.                 op := token;
  1285.                 fValue := GetFactor;
  1286.                 case op of
  1287.                     MulOp: 
  1288.                         tValue := tValue * fValue;
  1289.                     IntDivOp: 
  1290.                         if fValue <> 0.0 then
  1291.                             tValue := trunc(tValue) div trunc(fValue)
  1292.                         else
  1293.                             MacroError(DivideByZero);
  1294.                     ModOp: 
  1295.                         if fValue <> 0.0 then
  1296.                             tValue := trunc(tValue) mod trunc(fValue)
  1297.                         else
  1298.                             MacroError(DivideByZero);
  1299.                     DivOp: 
  1300.                         if fValue <> 0.0 then
  1301.                             tValue := tValue / fValue
  1302.                         else
  1303.                             MacroError(DivideByZero);
  1304.                     AndOp:  begin
  1305.                             CheckBoolean(tValue);
  1306.                             CheckBoolean(fValue);
  1307.                             tValue := ord((tValue = ord(true)) and (fValue = ord(true)));
  1308.                         end;
  1309.                 end; {case}
  1310.             end; {while}
  1311.         GetTerm := tValue;
  1312.     end;
  1313.  
  1314.  
  1315.     function GetSimpleExpression: extended;
  1316.         var
  1317.             seValue, tValue: extended;
  1318.             op: TokenType;
  1319.     begin
  1320.         seValue := GetTerm;
  1321.         while token in [PlusOp, MinusOp, OrOp] do begin
  1322.                 op := token;
  1323.                 tValue := GetTerm;
  1324.                 case op of
  1325.                     PlusOp: 
  1326.                         seValue := seValue + tValue;
  1327.                     MinusOp: 
  1328.                         seValue := seValue - tValue;
  1329.                     orOp:  begin
  1330.                             CheckBoolean(seValue);
  1331.                             CheckBoolean(tValue);
  1332.                             seValue := ord((seValue = ord(true)) or (tValue = ord(true)));
  1333.                         end;
  1334.                 end;
  1335.             end;
  1336.         GetSimpleExpression := seValue;
  1337.     end;
  1338.  
  1339.  
  1340.     function GetExpression: extended;
  1341.         var
  1342.             eValue, seValue: extended;
  1343.             op: TokenType;
  1344.     begin
  1345.         eValue := GetSimpleExpression;
  1346.         while token in [eqOp, ltOp, gtOp, neOp, leOp, geOp] do begin
  1347.                 op := token;
  1348.                 seValue := GetSimpleExpression;
  1349.                 case op of
  1350.                     eqOp: 
  1351.                         eValue := ord(eValue = seValue);
  1352.                     ltOp: 
  1353.                         eValue := ord(eValue < seValue);
  1354.                     gtOp: 
  1355.                         eValue := ord(eValue > seValue);
  1356.                     neOp: 
  1357.                         eValue := ord(eValue <> seValue);
  1358.                     leOp: 
  1359.                         eValue := ord(eValue <= seValue);
  1360.                     geOp: 
  1361.                         eValue := ord(eValue >= seValue);
  1362.                 end;
  1363.             end;
  1364.         GetExpression := eValue;
  1365.         PutTokenBack;
  1366.     end;
  1367.  
  1368.  
  1369. {$S}
  1370. {Routines from here to the end of the file go in the macro1 segment}
  1371.  
  1372.     procedure DoCapture;
  1373.     begin
  1374.         CaptureAndDisplayFrame;
  1375.         if ContinuousHistogram then
  1376.             ShowContinuousHistogram;
  1377.     end;
  1378.  
  1379.  
  1380.     procedure DoWait;
  1381.         var
  1382.             seconds: extended;
  1383.             SaveTicks: LongInt;
  1384.             str: str255;
  1385.     begin
  1386.         GetLeftParen;
  1387.         seconds := GetExpression;
  1388.         GetRightParen;
  1389.         if Token <> DoneT then begin
  1390.                 SaveTicks := TickCount + round(seconds * 60.0);
  1391.                 repeat
  1392.                     if Digitizing then
  1393.                         DoCapture;
  1394.                 until (TickCount > SaveTicks) or CommandPeriod;
  1395.             end;
  1396.     end;
  1397.  
  1398.  
  1399.     procedure SetDensitySlice; {LowerLevel,UpperLevel:integer}
  1400.   {Disable density slicing if lower and upper=0 and enable it up lower and upper=255}
  1401.         var
  1402.             sStart, sEnd: integer;
  1403.     begin
  1404.         GetLeftParen;
  1405.         sStart := GetInteger;
  1406.         RangeCheck(sStart);
  1407.         GetComma;
  1408.         sEnd := GetInteger;
  1409.         RangeCheck(sEnd);
  1410.         GetRightParen;
  1411.         if Token <> DoneT then begin
  1412.                 DisableDensitySlice;
  1413.                 DisableThresholding;
  1414.                 if (sEnd < sStart) or ((sStart = 0) and (sEnd = 0)) then
  1415.                     exit(SetDensitySlice);
  1416.                 if not ((sStart = 255) and (sEnd = 255)) then begin
  1417.                         SliceStart := sStart;
  1418.                         SliceEnd := sEnd;
  1419.                         if SliceStart < 1 then
  1420.                             SliceStart := 1;
  1421.                         if SliceEnd > 254 then
  1422.                             SliceEnd := 254;
  1423.                     end;
  1424.                 EnableDensitySlice;
  1425.             end;
  1426.     end;
  1427.  
  1428.  
  1429.     procedure SetColor;
  1430.         var
  1431.             index: integer;
  1432.             SaveCommand: CommandType;
  1433.     begin
  1434.         SaveCommand := MacroCommand;
  1435.         GetLeftParen;
  1436.         index := GetInteger;
  1437.         GetRightParen;
  1438.         RangeCheck(index);
  1439.         if Token <> DoneT then begin
  1440.                 if SaveCommand = SetForeC then
  1441.                     SetForegroundColor(index)
  1442.                 else
  1443.                     SetBackgroundColor(index);
  1444.             end;
  1445.     end;
  1446.  
  1447.  
  1448.     procedure DoConstantArithmetic;
  1449.         var
  1450.             constant: extended;
  1451.             SaveCommand: CommandType;
  1452.     begin
  1453.         SaveCommand := MacroCommand;
  1454.         GetLeftParen;
  1455.         constant := GetExpression;
  1456.         GetRightParen;
  1457.         if token <> DoneT then
  1458.             case SaveCommand of
  1459.                 AddConstC: 
  1460.                     DoArithmetic(AddItem, constant);
  1461.                 MulConstC: 
  1462.                     DoArithmetic(MultiplyItem, constant);
  1463.             end;
  1464.     end;
  1465.  
  1466.  
  1467.     procedure GetNextWindow;
  1468.         var
  1469.             n: integer;
  1470.     begin
  1471.         n := info^.PicNum + 1;
  1472.         if n > nPics then
  1473.             n := 1;
  1474.         StopDigitizing;
  1475.         SaveRoi;
  1476.         DisableDensitySlice;
  1477.         SelectWindow(PicWindow[n]);
  1478.         Info := pointer(WindowPeek(PicWindow[n])^.RefCon);
  1479.         ActivateWindow;
  1480.         GenerateValues;
  1481.         LoadLUT(info^.cTable);
  1482.         UpdatePicWindow;
  1483.     end;
  1484.  
  1485.  
  1486.     procedure DoRevert;
  1487.     begin
  1488.         if info^.revertable then begin
  1489.                 RevertToSaved;
  1490.                 UpdatePicWindow;
  1491.             end
  1492.         else
  1493.             MacroError('Unable to revert');
  1494.     end;
  1495.  
  1496.  
  1497.     procedure MakeRoi;
  1498.         var
  1499.             Left, Top, Width, Height: integer;
  1500.             SaveCommand: CommandType;
  1501.     begin
  1502.         SaveCommand := MacroCommand;
  1503.         GetLeftParen;
  1504.         left := GetInteger;
  1505.         GetComma;
  1506.         top := GetInteger;
  1507.         GetComma;
  1508.         width := GetInteger;
  1509.         if width < 1 then
  1510.             width := 1;
  1511.         GetComma;
  1512.         height := GetInteger;
  1513.         if height < 1 then
  1514.             height := 1;
  1515.         GetRightParen;
  1516.         KillRoi;
  1517.         if token <> DoneT then
  1518.             with Info^ do begin
  1519.                     StopDigitizing;
  1520.                     if SaveCommand = MakeOvalC then
  1521.                         RoiType := OvalRoi
  1522.                     else
  1523.                         RoiType := RectRoi;
  1524.                     SetRect(RoiRect, left, top, left + width, top + height);
  1525.                     MakeRegion;
  1526.                     SetupUndo;
  1527.                     RoiShowing := true;
  1528.                 end;
  1529.     end;
  1530.  
  1531.  
  1532.     procedure MoveRoi;
  1533.         var
  1534.             DeltaH, DeltaV: integer;
  1535.     begin
  1536.         GetLeftParen;
  1537.         DeltaH := GetInteger;
  1538.         GetComma;
  1539.         DeltaV := GetInteger;
  1540.         GetRightParen;
  1541.         with info^ do begin
  1542.                 if not RoiShowing then begin
  1543.                         MacroError('No Selection');
  1544.                         exit(MoveRoi);
  1545.                     end;
  1546.                 OffsetRgn(roiRgn, DeltaH, DeltaV);
  1547.                 RoiRect := roiRgn^^.rgnBBox;
  1548.                 RoiUpdateTime := 0;
  1549.                 MacroOpPending := true;
  1550.             end;
  1551.     end;
  1552.  
  1553.  
  1554.     procedure InsetRoi;
  1555.         var
  1556.             delta: integer;
  1557.     begin
  1558.         GetLeftParen;
  1559.         delta := GetInteger;
  1560.         GetRightParen;
  1561.         with info^ do begin
  1562.                 if not RoiShowing then begin
  1563.                         MacroError('No Selection');
  1564.                         exit(InsetRoi);
  1565.                     end;
  1566.                 InsetRgn(roiRgn, delta, delta);
  1567.                 RoiRect := roiRgn^^.rgnBBox;
  1568.                 RoiUpdateTime := 0;
  1569.                 MacroOpPending := true;
  1570.             end;
  1571.     end;
  1572.  
  1573.  
  1574.     procedure DoMoveTo; {(x,y:integer)}
  1575.     begin
  1576.         GetLeftParen;
  1577.         CurrentX := GetInteger;
  1578.         GetComma;
  1579.         CurrentY := GetInteger;
  1580.         GetRightParen;
  1581.         InsertionPoint.h := CurrentX;
  1582.         InsertionPoint.v := CurrentY + 4;
  1583.     end;
  1584.  
  1585.  
  1586.     procedure DoDrawtext (str: str255; EndOfLine: boolean);
  1587.     begin
  1588.         if info <> NoInfo then begin
  1589.                 KillRoi;
  1590.                 DrawTextString(str, InsertionPoint, TextJust);
  1591.                 if EndOfLine then begin
  1592.                         CurrentY := CurrentY + CurrentSize;
  1593.                         InsertionPoint.h := CurrentX;
  1594.                         InsertionPoint.v := CurrentY + 4;
  1595.                     end;
  1596.             end;
  1597.     end;
  1598.  
  1599.  
  1600.     procedure DrawNumber;
  1601.         var
  1602.             n: extended;
  1603.             str: str255;
  1604.             fwidth: integer;
  1605.     begin
  1606.         GetLeftParen;
  1607.         n := GetExpression;
  1608.         GetRightParen;
  1609.         if token <> DoneT then begin
  1610.                 if n = trunc(n) then
  1611.                     fwidth := 0
  1612.                 else
  1613.                     fwidth := precision;
  1614.                 RealToString(n, 1, fwidth, str);
  1615.                 DoDrawText(str, true);
  1616.             end;
  1617.     end;
  1618.  
  1619.  
  1620.     procedure SetFont;
  1621.         var
  1622.             FontName: str255;
  1623.             id: integer;
  1624.     begin
  1625.         FontName := GetStringArg;
  1626.         if Token <> DoneT then begin
  1627.                 GetFNum(FontName, id);
  1628.                 if id = 0 then
  1629.                     MacroError('Font not available')
  1630.                 else
  1631.                     CurrentFontID := id;
  1632.             end;
  1633.     end;
  1634.  
  1635.  
  1636.     procedure SetFontSize;
  1637.         var
  1638.             size: integer;
  1639.     begin
  1640.         GetLeftParen;
  1641.         Size := GetInteger;
  1642.         GetRightParen;
  1643.         if (size < 6) or (size > 720) then
  1644.             MacroError('Argument out of range');
  1645.         if Token <> DoneT then
  1646.             CurrentSize := size;
  1647.     end;
  1648.  
  1649.  
  1650.     procedure SetText;
  1651.         var
  1652.             Attributes: str255;
  1653.     begin
  1654.         Attributes := GetStringArg;
  1655.         if Token <> DoneT then begin
  1656.                 MakeLowerCase(Attributes);
  1657.                 if pos('with', Attributes) <> 0 then
  1658.                     TextBack := WithBack;
  1659.                 if pos('no', Attributes) <> 0 then
  1660.                     TextBack := NoBack;
  1661.                 if pos('left', Attributes) <> 0 then
  1662.                     TextJust := teJustLeft;
  1663.                 if pos('center', Attributes) <> 0 then
  1664.                     TextJust := teJustCenter;
  1665.                 if pos('right', Attributes) <> 0 then
  1666.                     TextJust := teJustRight;
  1667.                 CurrentStyle := [];
  1668.                 if pos('bold', Attributes) <> 0 then
  1669.                     CurrentStyle := CurrentStyle + [Bold];
  1670.                 if pos('italic', Attributes) <> 0 then
  1671.                     CurrentStyle := CurrentStyle + [Italic];
  1672.                 if pos('underline', Attributes) <> 0 then
  1673.                     CurrentStyle := CurrentStyle + [Underline];
  1674.                 if pos('outline', Attributes) <> 0 then
  1675.                     CurrentStyle := CurrentStyle + [Outline];
  1676.                 if pos('shadow', Attributes) <> 0 then
  1677.                     CurrentStyle := CurrentStyle + [Shadow];
  1678.             end;
  1679.     end;
  1680.  
  1681.  
  1682.     procedure DoPutMessage;
  1683.         var
  1684.             str: str255;
  1685.     begin
  1686.         GetArguments(str);
  1687.         if Token <> DoneT then
  1688.             PutMessage(str)
  1689.     end;
  1690.  
  1691.  
  1692.     function GetVar: integer;
  1693.     begin
  1694.         GetVar := 0;
  1695.         GetToken;
  1696.         if token <> Variable then
  1697.             MacroError('Variable expected')
  1698.         else
  1699.             GetVar := TokenStackLoc;
  1700.     end;
  1701.  
  1702.  
  1703.     procedure GetPicSize;  {(width,height)}
  1704.         var
  1705.             loc1, loc2: integer;
  1706.     begin
  1707.         GetLeftParen;
  1708.         loc1 := GetVar;
  1709.         GetComma;
  1710.         loc2 := GetVar;
  1711.         GetRightParen;
  1712.         if Token <> DoneT then
  1713.             with MacrosP^ do
  1714.                 if info = NoInfo then begin
  1715.                         stack[loc1].value := 0.0;
  1716.                         stack[loc2].value := 0.0;
  1717.                     end
  1718.                 else
  1719.                     with info^ do begin
  1720.                             stack[loc1].value := PixelsPerLine;
  1721.                             stack[loc2].value := nLines;
  1722.                         end;
  1723.     end;
  1724.  
  1725.  
  1726.     procedure GetRoi;  {(hloc,vloc,width,height)}
  1727.         var
  1728.             loc1, loc2, loc3, loc4: integer;
  1729.     begin
  1730.         GetLeftParen;
  1731.         loc1 := GetVar;
  1732.         GetComma;
  1733.         loc2 := GetVar;
  1734.         GetComma;
  1735.         loc3 := GetVar;
  1736.         GetComma;
  1737.         loc4 := GetVar;
  1738.         GetRightParen;
  1739.         if Token <> DoneT then
  1740.             with MacrosP^, Info^ do
  1741.                 if RoiShowing then
  1742.                     with RoiRect do begin
  1743.                             stack[loc1].value := left;
  1744.                             stack[loc2].value := top;
  1745.                             stack[loc3].value := right - left;
  1746.                             stack[loc4].value := bottom - top;
  1747.                         end
  1748.                 else begin
  1749.                         stack[loc1].value := 0.0;
  1750.                         stack[loc2].value := 0.0;
  1751.                         stack[loc3].value := 0.0;
  1752.                         stack[loc4].value := 0.0;
  1753.                     end;
  1754.     end;
  1755.  
  1756.  
  1757.     procedure CaptureOneFrame;
  1758.     begin
  1759.         if (FrameGrabber <> QuickCapture) and (FrameGrabber <> ScionLG3) then
  1760.             MacroError('Frame grabber not installed')
  1761.         else begin
  1762.                 StartDigitizing;
  1763.                 CaptureAndDisplayFrame;
  1764.                 StopDigitizing;
  1765.             end;
  1766.     end;
  1767.  
  1768.  
  1769.     procedure DoMakeNewWindow; {(name:str255)}
  1770.         var
  1771.             name: str255;
  1772.     begin
  1773.         GetArguments(name);
  1774.         if token <> DoneT then
  1775.             if (LongInt(NewPicWidth) * NewPicHeight) > UndoBufSize then
  1776.                 MacroError('New window larger than Undo buffer')
  1777.             else if not NewPicWindow(name, NewPicWidth, NewPicHeight) then
  1778.                 MacroError('Out of memory');
  1779.     end;
  1780.  
  1781.  
  1782.     procedure DoSetPalette;
  1783.         var
  1784.             PaletteType: str255;
  1785.             ok: boolean;
  1786.     begin
  1787.         PaletteType := GetStringArg;
  1788.         if token <> DoneT then begin
  1789.                 MakeLowerCase(PaletteType);
  1790.                 if pos('gray', PaletteType) <> 0 then
  1791.                     ResetGrayMap
  1792.                 else if pos('pseudo', PaletteType) <> 0 then
  1793.                     SwitchColorTables(Pseudo20Item, true)
  1794.                 else if pos('system', PaletteType) <> 0 then
  1795.                     SwitchColorTables(SystemPaletteItem, true)
  1796.                 else if pos('rainbow', PaletteType) <> 0 then
  1797.                     SwitchColorTables(RainbowItem, true)
  1798.                 else if pos('spectrum', PaletteType) <> 0 then
  1799.                     SwitchColorTables(SpectrumItem, true)
  1800.             end;
  1801.     end;
  1802.  
  1803.  
  1804.     procedure DoOpenImage;
  1805.         var
  1806.             err: OSErr;
  1807.             f: integer;
  1808.             FileFound, result: boolean;
  1809.             fname: str255;
  1810.             SaveCommand: CommandType;
  1811.     begin
  1812.         SaveCommand := MacroCommand;
  1813.         GetArguments(fname);
  1814.         if token <> DoneT then begin
  1815.                 if fname = '' then
  1816.                     fname := DefaultFileName;
  1817.                 err := fsopen(fname, DefaultRefNum, f);
  1818.                 FileFound := err = NoErr;
  1819.                 err := fsclose(f);
  1820.                 if FileFound then
  1821.                     case SaveCommand of
  1822.                         OpenC: 
  1823.                             result := DoOpen(fname, DefaultRefNum);
  1824.                         ImportC: 
  1825.                             result := ImportFile(fname, DefaultRefNum);
  1826.                     end
  1827.                 else
  1828.                     case SaveCommand of
  1829.                         OpenC: 
  1830.                             result := DoOpen('', 0);
  1831.                         ImportC: 
  1832.                             result := ImportFile('', 0);
  1833.                     end;
  1834.                 if result then
  1835.                     UpdatePicWindow
  1836.                 else
  1837.                     token := DoneT;
  1838.             end;
  1839.     end;
  1840.  
  1841.  
  1842.     procedure SetImportAttributes;
  1843.         var
  1844.             Attributes: str255;
  1845.     begin
  1846.         Attributes := GetStringArg;
  1847.         if Token <> DoneT then begin
  1848.                 MakeLowerCase(Attributes);
  1849.                 WhatToImport := ImportTIFF;
  1850.                 ImportCustomDepth := EightBits;
  1851.                 ImportSwapBytes := false;
  1852.                 ImportCalibrate := false;
  1853.                 ImportAll := false;
  1854.                 ImportAutoScale := true;
  1855.                 ImportInvert := false;
  1856.                 if pos('mcid', Attributes) <> 0 then
  1857.                     WhatToImport := ImportMCID;
  1858.                 if pos('look', Attributes) <> 0 then
  1859.                     WhatToImport := ImportLUT;
  1860.                 if pos('palette', Attributes) <> 0 then
  1861.                     WhatToImport := ImportLUT;
  1862.                 if pos('text', Attributes) <> 0 then
  1863.                     WhatToImport := ImportText;
  1864.                 if pos('custom', Attributes) <> 0 then
  1865.                     WhatToImport := ImportCustom;
  1866.                 if (pos('8', Attributes) <> 0) or (pos('eight', Attributes) <> 0) then begin
  1867.                         ImportCustomDepth := EightBits;
  1868.                         WhatToImport := ImportCustom;
  1869.                     end;
  1870.                 if (pos('signed', Attributes) <> 0) then begin
  1871.                         ImportCustomDepth := SixteenBitsSigned;
  1872.                         WhatToImport := ImportCustom;
  1873.                     end;
  1874.                 if (pos('unsigned', Attributes) <> 0) then begin
  1875.                         ImportCustomDepth := SixteenBitsUnsigned;
  1876.                         WhatToImport := ImportCustom;
  1877.                     end;
  1878.                 if (pos('swap', Attributes) <> 0) then
  1879.                     ImportSwapBytes := true;
  1880.                 if (pos('calibrate', Attributes) <> 0) then
  1881.                     ImportCalibrate := true;
  1882.                 if (pos('fixed', Attributes) <> 0) then
  1883.                     ImportAutoScale := false;
  1884.                 if (pos('all', Attributes) <> 0) then
  1885.                     ImportAll := true;
  1886.                 if (pos('invert', Attributes) <> 0) then
  1887.                     ImportInvert := true;
  1888.             end;
  1889.     end;
  1890.  
  1891.  
  1892.     procedure SetImportMinMax; {(min,max:integer)}
  1893.         var
  1894.             TempMin, TempMax: extended;
  1895.     begin
  1896.         GetLeftParen;
  1897.         TempMin := GetExpression;
  1898.         GetComma;
  1899.         TempMax := GetExpression;
  1900.         GetRightParen;
  1901.         if Token <> DoneT then begin
  1902.                 ImportAutoScale := false;
  1903.                 ImportMin := TempMin;
  1904.                 ImportMax := TempMax;
  1905.             end;
  1906.     end;
  1907.  
  1908.  
  1909.     procedure SetCustomImport; {(width,height,offset[,nslices]:integer)}
  1910.         var
  1911.             width, height, nSlices: integer;
  1912.             offset: LongInt;
  1913.     begin
  1914.         GetLeftParen;
  1915.         width := GetInteger;
  1916.         GetComma;
  1917.         height := GetInteger;
  1918.         GetComma;
  1919.         offset := GetInteger;
  1920.         GetToken;
  1921.         if token = comma then
  1922.             nSlices := GetInteger
  1923.         else begin
  1924.                 PutTokenBack;
  1925.                 nSlices := 1
  1926.             end;
  1927.         GetRightParen;
  1928.         if (width < 0) or (width > MaxPicSize) or (height < 0) or (offset < 0) or (nSlices < 1) then
  1929.             MacroError('Argument out of range');
  1930.         if Token <> DoneT then begin
  1931.                 ImportCustomWidth := width;
  1932.                 ImportCustomHeight := height;
  1933.                 ImportCustomOffset := offset;
  1934.                 ImportCustomSlices := nSlices;
  1935.                 WhatToImport := ImportCustom;
  1936.             end;
  1937.     end;
  1938.  
  1939.  
  1940.     procedure SelectImage (id: integer);
  1941.     begin
  1942.         StopDigitizing;
  1943.         SaveRoi;
  1944.         DisableDensitySlice;
  1945.         SelectWindow(PicWindow[id]);
  1946.         Info := pointer(WindowPeek(PicWindow[id])^.RefCon);
  1947.         ActivateWindow;
  1948.         GenerateValues;
  1949.         LoadLUT(info^.cTable);
  1950.         UpdatePicWindow;
  1951.     end;
  1952.  
  1953.  
  1954.     procedure SelectPic; {(PicN:integer)}
  1955.         var
  1956.             PicN, i: integer;
  1957.             SaveCommand: CommandType;
  1958.     begin
  1959.         SaveCommand := MacroCommand;
  1960.         GetLeftParen;
  1961.         PicN := GetInteger;
  1962.         GetRightParen;
  1963.         i := 0;
  1964.         while (PicN < 0) and (i < nPics) do begin
  1965.                 i := i + 1;
  1966.                 if InfoPtr(WindowPeek(PicWindow[i])^.RefCon)^.pidNum = PicN then
  1967.                     PicN := i;
  1968.             end;
  1969.         if (PicN < 1) or (PicN > nPics) then
  1970.             MacroError('Specified image does not exist');
  1971.         if Token <> DoneT then begin
  1972.                 if SaveCommand = SelectPicC then
  1973.                     SelectImage(PicN)
  1974.                 else
  1975.                     Info := pointer(WindowPeek(PicWindow[PicN])^.RefCon);
  1976.             end;
  1977.     end;
  1978.  
  1979.  
  1980.     procedure SetPicName;  {(name:string)}
  1981.         var
  1982.             n, i: LongInt;
  1983.             isInteger: boolean;
  1984.             name: str255;
  1985.     begin
  1986.         GetArguments(name);
  1987.         if Token <> DoneT then begin
  1988.                 with info^ do begin
  1989.                         title := name;
  1990.                         if PictureType <> FrameGrabberType then
  1991.                             PictureType := NewPicture;
  1992.                         UpdateWindowsMenuItem(PixMapSize, title, PicNum);
  1993.                         UpdateTitleBar;
  1994.                     end;
  1995.             end;
  1996.     end;
  1997.  
  1998.  
  1999.     procedure SetNewSize; {(width,height:integer)}
  2000.         var
  2001.             TempWidth, TempHeight: integer;
  2002.     begin
  2003.         GetLeftParen;
  2004.         TempWidth := GetInteger;
  2005.         GetComma;
  2006.         TempHeight := GetInteger;
  2007.         GetRightParen;
  2008.         if Token <> DoneT then begin
  2009.                 NewPicWidth := TempWidth;
  2010.                 NewPicHeight := TempHeight;
  2011.                 if odd(NewPicWidth) then
  2012.                     NewPicWidth := NewPicWidth + 1;
  2013.                 if NewPicWidth > MaxPicSize then
  2014.                     NewPicWidth := MaxPicSize;
  2015.                 if NewPicWidth < 8 then
  2016.                     NewPicWidth := 8;
  2017.                 if NewPicHeight < 8 then
  2018.                     NewPicHeight := 8;
  2019.                 if NewPicHeight > MaxPicSize then
  2020.                     NewPicHeight := MaxPicSize;
  2021.             end;
  2022.     end;
  2023.  
  2024.  
  2025.     procedure DoSaveAs;
  2026.         var
  2027.             name: str255;
  2028.             RefNum: integer;
  2029.             HasArgs: boolean;
  2030.     begin
  2031.         name := info^.title;
  2032.         if (name = 'Untitled') or (name = 'Camera') then
  2033.             name := '';
  2034.         GetToken;
  2035.         HasArgs := token = LeftParen;
  2036.         PutTokenBack;
  2037.         if HasArgs then
  2038.             GetArguments(name);
  2039.         if token <> DoneT then begin
  2040.                 StopDigitizing;
  2041.                 if nSaves = 0 then
  2042.                     RefNum := 0
  2043.                 else
  2044.                     RefNum := DefaultRefNum;
  2045.                 case CurrentWindow of
  2046.                     TextKind: 
  2047.                         SaveTextAs;
  2048.                     ResultsKind: 
  2049.                         Export('', RefNum);
  2050.                     otherwise begin
  2051.                             if info <> NoInfo then
  2052.                                 SaveAs(name, RefNum)
  2053.                             else
  2054.                                 MacroError(NoImageOpen);
  2055.                         end;
  2056.                 end;
  2057.                 nSaves := nSaves + 1;
  2058.             end;
  2059.     end;
  2060.  
  2061.  
  2062.     procedure DoSave;
  2063.         var
  2064.             kind: integer;
  2065.     begin
  2066.         StopDigitizing;
  2067.         kind := CurrentWindow;
  2068.         if (kind = PicKind) or (kind = TextKind) or (Kind = ResultsKind) then
  2069.             SaveFile
  2070.         else
  2071.             MacroError('Nothing to save');
  2072.     end;
  2073.  
  2074.  
  2075.     procedure DoExport;
  2076.         var
  2077.             name: str255;
  2078.             RefNum: integer;
  2079.             HasArgs: boolean;
  2080.     begin
  2081.         StopDigitizing;
  2082.         name := info^.title;
  2083.         if (name = 'Untitled') or (name = 'Camera') then
  2084.             name := '';
  2085.         GetToken;
  2086.         HasArgs := token = LeftParen;
  2087.         PutTokenBack;
  2088.         if HasArgs then
  2089.             GetArguments(name);
  2090.         if nSaves = 0 then
  2091.             RefNum := 0
  2092.         else
  2093.             RefNum := DefaultRefNum;
  2094.         Export(name, RefNum);
  2095.         nSaves := nSaves + 1;
  2096.     end;
  2097.  
  2098.  
  2099.     procedure DoCopyResults;
  2100.         var
  2101.             IgnoreResult: boolean;
  2102.     begin
  2103.         if mCount < 1 then
  2104.             MacroError('Copy Results failed')
  2105.         else begin
  2106.                 CopyResults;
  2107.                 IgnoreResult := SystemEdit(3); {Fake Copy needed for MultiFinder}
  2108.             end;
  2109.     end;
  2110.  
  2111.  
  2112.     procedure DisposeAll;
  2113.         var
  2114.             i, ignore: integer;
  2115.     begin
  2116.         StopDigitizing;
  2117.         for i := nPics downto 1 do begin
  2118.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  2119.                 ignore := CloseAWindow(info^.wptr);
  2120.             end;
  2121.     end;
  2122.  
  2123.  
  2124.     procedure DoDuplicate;
  2125.         var
  2126.             str: str255;
  2127.     begin
  2128.         GetArguments(str);
  2129.         if token <> DoneT then
  2130.             if not Duplicate(str, false) then
  2131.                 token := DoneT
  2132.             else
  2133.                 UpdatePicWindow;
  2134.     end;
  2135.  
  2136.  
  2137.     procedure DoLineTo; {(x,y:integer)}
  2138.         var
  2139.             x, y: integer;
  2140.             p1, p2: point;
  2141.     begin
  2142.         GetLeftParen;
  2143.         p2.h := GetInteger;
  2144.         GetComma;
  2145.         p2.v := GetInteger;
  2146.         GetRightParen;
  2147.         if token <> DoneT then begin
  2148.                 KillRoi;
  2149.                 p1.h := CurrentX;
  2150.                 p1.v := CurrentY;
  2151.                 CurrentX := p2.h;
  2152.                 CurrentY := p2.v;
  2153.                 OffscreenToScreen(p1);
  2154.                 OffscreenToScreen(p2);
  2155.                 DrawObject(LineObj, p1, p2);
  2156.             end;
  2157.     end;
  2158.  
  2159.  
  2160.     procedure DoGetLine;  {(var x1,y1,x2,y2:real; LineWidth:integer)}
  2161.         var
  2162.             loc1, loc2, loc3, loc4, loc5: integer;
  2163.             x1, y1, x2, y2: real;
  2164.     begin
  2165.         GetLeftParen;
  2166.         loc1 := GetVar;
  2167.         GetComma;
  2168.         loc2 := GetVar;
  2169.         GetComma;
  2170.         loc3 := GetVar;
  2171.         GetComma;
  2172.         loc4 := GetVar;
  2173.         GetComma;
  2174.         loc5 := GetVar;
  2175.         GetRightParen;
  2176.         if Token <> DoneT then
  2177.             with MacrosP^, info^ do begin
  2178.                     GetLoi(x1, y1, x2, y2);
  2179.                     if RoiShowing and (RoiType = LineRoi) then
  2180.                         stack[loc1].value := x1
  2181.                     else
  2182.                         stack[loc1].value := -1;
  2183.                     stack[loc2].value := y1;
  2184.                     stack[loc3].value := x2;
  2185.                     stack[loc4].value := y2;
  2186.                     stack[loc5].value := LineWidth;
  2187.                 end;
  2188.     end;
  2189.  
  2190.  
  2191.     procedure DoScaleAndRotate; {(hscale,vscale,angle:real)}
  2192.         var
  2193.             SaveCommand: CommandType;
  2194.     begin
  2195.         SaveCommand := MacroCommand;
  2196.         GetLeftParen;
  2197.         rsHScale := GetExpression;
  2198.         GetComma;
  2199.         rsVScale := GetExpression;
  2200.         if SaveCommand <> ScaleSelectionC then begin
  2201.                 GetComma;
  2202.                 rsAngle := GetExpression;
  2203.             end;
  2204.         GetRightParen;
  2205.         if token <> DoneT then begin
  2206.                 if SaveCommand = ScaleSelectionC then begin
  2207.                         rsMethod := NearestNeighbor;
  2208.                         rsCreateNewWindow := false;
  2209.                         rsAngle := 0.0;
  2210.                     end;
  2211.                 ScaleAndRotate;
  2212.             end;
  2213.     end;
  2214.  
  2215.  
  2216.     procedure SetPlotScale; {(min,max:integer)}
  2217.         var
  2218.             min, max: extended;
  2219.     begin
  2220.         GetLeftParen;
  2221.         min := GetExpression;
  2222.         GetComma;
  2223.         max := GetExpression;
  2224.         GetRightParen;
  2225.         if not info^.DensityCalibrated then begin
  2226.                 RangeCheck(trunc(min));
  2227.                 RangeCheck(trunc(max));
  2228.             end;
  2229.         if token <> DoneT then begin
  2230.                 AutoScalePlots := (min = 0.0) and (max = 0.0);
  2231.                 ProfilePlotMin := min;
  2232.                 ProfilePlotMax := max;
  2233.             end;
  2234.     end;
  2235.  
  2236.  
  2237.     procedure SetPlotDimensions; {(width,height:integer)}
  2238.         var
  2239.             width, height: integer;
  2240.     begin
  2241.         GetLeftParen;
  2242.         width := GetInteger;
  2243.         GetComma;
  2244.         height := GetInteger;
  2245.         GetRightParen;
  2246.         if token <> DoneT then begin
  2247.                 FixedSizePlot := not ((width = 0) and (height = 0));
  2248.                 ProfilePlotWidth := width;
  2249.                 ProfilePlotHeight := height;
  2250.             end;
  2251.     end;
  2252.  
  2253.  
  2254.     procedure GetResults;  {(var n,mean,mode,min,max:real)}
  2255.         var
  2256.             loc1, loc2, loc3, loc4, loc5: integer;
  2257.     begin
  2258.         GetLeftParen;
  2259.         loc1 := GetVar;
  2260.         GetComma;
  2261.         loc2 := GetVar;
  2262.         GetComma;
  2263.         loc3 := GetVar;
  2264.         GetComma;
  2265.         loc4 := GetVar;
  2266.         GetComma;
  2267.         loc5 := GetVar;
  2268.         GetRightParen;
  2269.         if mCount = 0 then
  2270.             MacroError('No results');
  2271.         if Token <> DoneT then
  2272.             with MacrosP^, results do begin
  2273.                     stack[loc1].value := PixelCount^[mCount];
  2274.                     stack[loc2].value := UncalibratedMean;
  2275.                     stack[loc3].value := imode;
  2276.                     stack[loc4].value := MinIndex;
  2277.                     stack[loc5].value := MaxIndex;
  2278.                 end;
  2279.     end;
  2280.  
  2281.  
  2282.     procedure DoPasteOperation;
  2283.     begin
  2284.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  2285.                 MacroError('Not pasting');
  2286.                 exit(DoPasteOperation);
  2287.             end;
  2288.         if MacroCommand in [AddC, SubC, MulC, DivC] then begin
  2289.                 case MacroCommand of
  2290.                     AddC: 
  2291.                         CurrentOp := AddOp;
  2292.                     SubC: 
  2293.                         CurrentOp := SubtractOp;
  2294.                     MulC: 
  2295.                         CurrentOp := MultiplyOp;
  2296.                     DivC: 
  2297.                         CurrentOp := DivideOp;
  2298.                 end;
  2299.                 DoPasteMath;
  2300.                 exit(DoPasteOperation);
  2301.             end;
  2302.         case MacroCommand of
  2303.             CopyModeC: 
  2304.                 SetPasteMode(CopyModeItem);
  2305.             AndC: 
  2306.                 SetPasteMode(AndItem);
  2307.             OrC: 
  2308.                 SetPasteMode(OrItem);
  2309.             XorC: 
  2310.                 SetPasteMode(XorItem);
  2311.             ReplaceC: 
  2312.                 SetPasteMode(ReplaceItem);
  2313.             BlendC: 
  2314.                 SetPasteMode(BlendItem);
  2315.         end;
  2316.         if OptionKeyWasDown then begin
  2317.                 if PasteControl <> nil then
  2318.                     DrawPasteControl;
  2319.             end
  2320.         else
  2321.             KillRoi;
  2322.     end;
  2323.  
  2324.  
  2325.     procedure SetWidth; {(width:integer)}
  2326.         var
  2327.             width: integer;
  2328.     begin
  2329.         GetLeftParen;
  2330.         width := GetInteger;
  2331.         GetRightParen;
  2332.         if (Token <> DoneT) and (width > 0) then begin
  2333.                 LineWidth := width;
  2334.                 ShowLIneWidth;
  2335.             end;
  2336.     end;
  2337.  
  2338.  
  2339.     function GetMType (index: integer): MeasurementTypes;
  2340.     begin
  2341.         case index of
  2342.             0: 
  2343.                 GetMType := AreaM;
  2344.             1: 
  2345.                 GetMType := MeanM;
  2346.             2: 
  2347.                 GetMType := StdDevM;
  2348.             3: 
  2349.                 GetMType := xyLocM;
  2350.             4: 
  2351.                 GetMType := ModeM;
  2352.             5: 
  2353.                 GetMType := LengthM;
  2354.             6: 
  2355.                 GetMType := MajorAxisM;
  2356.             7: 
  2357.                 GetMType := MinorAxisM;
  2358.             8: 
  2359.                 GetMType := AngleM;
  2360.             9: 
  2361.                 GetMType := IntDenM;
  2362.             10: 
  2363.                 GetMType := MinMaxM;
  2364.             11: 
  2365.                 GetMType := User1M;
  2366.             12: 
  2367.                 GetMType := User2M;
  2368.         end;
  2369.     end;
  2370.  
  2371.  
  2372.     procedure SetPrecision; {(DigitsRightofDecimalPoint[,FieldWidth]:integer)}
  2373.         var
  2374.             digits, width: LongInt;
  2375.     begin
  2376.         GetLeftParen;
  2377.         digits := GetInteger;
  2378.         GetToken;
  2379.         if token = comma then
  2380.             width := GetInteger
  2381.         else
  2382.             PutTokenBack;
  2383.         GetRightParen;
  2384.         if Token <> DoneT then begin
  2385.                 if (digits >= 0) and (digits <= 12) then
  2386.                     precision := digits;
  2387.                 if (width >= 1) and (width <= 18) then
  2388.                     FieldWidth := width;
  2389.             end;
  2390.     end;
  2391.  
  2392.  
  2393.     procedure SetParticleSize; {(min,max:LongInt)}
  2394.         var
  2395.             min, max: LongInt;
  2396.     begin
  2397.         GetLeftParen;
  2398.         min := GetInteger;
  2399.         GetComma;
  2400.         max := GetInteger;
  2401.         GetRightParen;
  2402.         if Token <> DoneT then begin
  2403.                 MinParticleSize := min;
  2404.                 MaxParticleSize := max;
  2405.             end;
  2406.     end;
  2407.  
  2408.  
  2409.     procedure SetThreshold; {(level:integer)}
  2410.         var
  2411.             level: LongInt;
  2412.     begin
  2413.         GetLeftParen;
  2414.         level := GetInteger;
  2415.         GetRightParen;
  2416.         if level = -1 then begin
  2417.                 DisableThresholding;
  2418.                 exit(SetThreshold);
  2419.             end;
  2420.         RangeCheck(level);
  2421.         if Token <> DoneT then
  2422.             EnableThresholding(level);
  2423.     end;
  2424.  
  2425.  
  2426.     procedure DoPutPixel; {(hloc,vloc, value:integer)}
  2427.         var
  2428.             hloc, vloc, value: integer;
  2429.             MaskRect: rect;
  2430.     begin
  2431.         GetLeftParen;
  2432.         hloc := GetInteger;
  2433.         GetComma;
  2434.         vloc := GetInteger;
  2435.         GetComma;
  2436.         value := GetInteger;
  2437.         GetRightParen;
  2438.         if (Token <> DoneT) and (info <> NoInfo) then begin
  2439.                 KillRoi;
  2440.                 PutPixel(hloc, vloc, value);
  2441.                 SetRect(MaskRect, hloc, vloc, hloc + 1, vloc + 1);
  2442.                 UpdateScreen(MaskRect);
  2443.             end;
  2444.     end;
  2445.  
  2446.  
  2447.     procedure CloseWindow;
  2448.         var
  2449.             OldPicNum, NewPicNum, ignore: integer;
  2450.     begin
  2451.         if CurrentWindow <> PicKind then begin
  2452.                 ignore := CloseAWindow(CurrentWPtr);
  2453.                 exit(CloseWindow);
  2454.             end;
  2455.         if info = NoInfo then begin
  2456.                 MacroError(NoImageOpen);
  2457.                 exit(CloseWindow);
  2458.             end;
  2459.         StopDigitizing;
  2460.         SaveRoi;
  2461.         with info^ do begin
  2462.                 OldPicNum := PicNum;
  2463.                 ignore := CloseAWindow(wptr);
  2464.             end;
  2465.         if nPics >= 1 then begin
  2466.                 NewPicNum := OldPicNum - 1;
  2467.                 if NewPicNum < 1 then
  2468.                     NewPicNum := 1;
  2469.                 SelectImage(NewPicNum);
  2470.             end;
  2471.     end;
  2472.  
  2473.  
  2474.     procedure SetScaling;
  2475.         var
  2476.             ScalingOptions: str255;
  2477.             ok: boolean;
  2478.     begin
  2479.         ScalingOptions := GetStringArg;
  2480.         if token <> DoneT then begin
  2481.                 MakeLowerCase(ScalingOptions);
  2482.                 rsInteractive := false;
  2483.                 if pos('bilinear', ScalingOptions) <> 0 then
  2484.                     rsMethod := Bilinear;
  2485.                 if pos('nearest', ScalingOptions) <> 0 then
  2486.                     rsMethod := NearestNeighbor;
  2487.                 if pos('new', ScalingOptions) <> 0 then
  2488.                     rsCreateNewWindow := true;
  2489.                 if pos('same', ScalingOptions) <> 0 then
  2490.                     rsCreateNewWindow := false;
  2491.                 if pos('interactive', ScalingOptions) <> 0 then
  2492.                     rsInteractive := true;
  2493.             end;
  2494.     end;
  2495.  
  2496.  
  2497.     procedure DoChangeValues; {(v1,v2,v3:integer)}
  2498.         var
  2499.             v1, v2, v3: integer;
  2500.     begin
  2501.         GetLeftParen;
  2502.         v1 := GetInteger;
  2503.         GetComma;
  2504.         v2 := GetInteger;
  2505.         GetComma;
  2506.         v3 := GetInteger;
  2507.         GetRightParen;
  2508.         RangeCheck(v1);
  2509.         RangeCheck(v2);
  2510.         RangeCheck(v3);
  2511.         if Token <> DoneT then
  2512.             ChangeValues(v1, v2, v3);
  2513.     end;
  2514.  
  2515.  
  2516.     procedure DoGetMouse;  {(var x,y:integer)}
  2517.         var
  2518.             loc1, loc2, sh, sv: integer;
  2519.             loc: point;
  2520.     begin
  2521.         GetLeftParen;
  2522.         loc1 := GetVar;
  2523.         GetComma;
  2524.         loc2 := GetVar;
  2525.         GetRightParen;
  2526.         if Token <> DoneT then
  2527.             with MacrosP^ do begin
  2528.                     SetPort(info^.wptr);
  2529.                     GetMouse(loc);
  2530.                     with loc do begin
  2531.                             sh := h;
  2532.                             sv := v;
  2533.                             ScreenToOffscreen(loc);
  2534.                             if sh < 0 then
  2535.                                 h := sh;
  2536.                             if sv < 0 then
  2537.                                 v := sv;
  2538.                             stack[loc1].value := h;
  2539.                             stack[loc2].value := v;
  2540.                         end;
  2541.                 end;
  2542.     end;
  2543.  
  2544.  
  2545.     procedure DoRotate (cmd: CommandType);
  2546.         var
  2547.             NoBoolean, NewWindow: boolean;
  2548.     begin
  2549.         GetToken;
  2550.         noBoolean := token <> LeftParen;
  2551.         PutTokenBack;
  2552.         if NoBoolean then
  2553.             NewWindow := false
  2554.         else
  2555.             NewWindow := GetBooleanArg;
  2556.         if NewWindow then begin
  2557.                 case cmd of
  2558.                     RotateRC: 
  2559.                         RotateToNewWindow(RotateRight);
  2560.                     RotateLC: 
  2561.                         RotateToNewWindow(RotateLeft)
  2562.                 end;
  2563.                 if not macro then
  2564.                     MacroError('Rotate failed')
  2565.             end
  2566.         else
  2567.             case cmd of
  2568.                 RotateRC: 
  2569.                     FlipOrRotate(RotateRight);
  2570.                 RotateLC: 
  2571.                     FlipOrRotate(RotateLeft)
  2572.             end;
  2573.     end;
  2574.  
  2575.  
  2576.     procedure DoSelectSlice; {(SliceNumber:integer)}
  2577.         var
  2578.             SliceNumber: LongInt;
  2579.             isRoi: boolean;
  2580.             SaveCommand: CommandType;
  2581.     begin
  2582.         SaveCommand := MacroCommand;
  2583.         GetLeftParen;
  2584.         SliceNumber := GetInteger;
  2585.         GetRightParen;
  2586.         with info^, info^.StackInfo^ do begin
  2587.                 if (SliceNumber < 1) or (SliceNumber > nSlices) then
  2588.                     MacroError('Illegal slice number');
  2589.                 if Token <> DoneT then begin
  2590.                         isRoi := RoiShowing;
  2591.                         if isRoi then
  2592.                             KillRoi;
  2593.                         CurrentSlice := SliceNumber;
  2594.                         SelectSlice(CurrentSlice);
  2595.                         if SaveCommand = SelectSliceC then begin
  2596.                                 UpdatePicWindow;
  2597.                                 UpdateTitleBar;
  2598.                             end;
  2599.                         if isRoi then
  2600.                             RestoreRoi;
  2601.                     end;
  2602.             end;
  2603.     end;
  2604.  
  2605.  
  2606.     procedure MakeNewStack; {(name:str255)}
  2607.         var
  2608.             name: str255;
  2609.             aok: boolean;
  2610.     begin
  2611.         GetArguments(name);
  2612.         if token <> DoneT then
  2613.             if (LongInt(NewPicWidth) * NewPicHeight) > UndoBufSize then
  2614.                 MacroError('Stack larger than Undo Buffer')
  2615.             else if NewPicWindow(name, NewPicWidth, NewPicHeight) then
  2616.                 if not MakeStackFromWindow then
  2617.                     MacroError('Out of memory');
  2618.     end;
  2619.  
  2620.  
  2621.     procedure MakeLineRoi; {(x1,y1,x2,y2:real)}
  2622.         var
  2623.             x1, y1, x2, y2: real;
  2624.     begin
  2625.         GetLeftParen;
  2626.         x1 := GetExpression;
  2627.         GetComma;
  2628.         y1 := GetExpression;
  2629.         GetComma;
  2630.         x2 := GetExpression;
  2631.         GetComma;
  2632.         y2 := GetExpression;
  2633.         GetRightParen;
  2634.         if token <> DoneT then
  2635.             with Info^ do begin
  2636.                     KillRoi;
  2637.                     StopDigitizing;
  2638.                     LX1 := x1;
  2639.                     LY1 := y1;
  2640.                     LX2 := x2;
  2641.                     LY2 := y2;
  2642.                     RoiType := LineRoi;
  2643.                     MakeRegion;
  2644.                     SetupUndo;
  2645.                     RoiShowing := true;
  2646.                 end;
  2647.     end;
  2648.  
  2649.  
  2650.     procedure DoGetTime;
  2651.         var
  2652.             date: DateTimeRec;
  2653.             loc1, loc2, loc3, loc4, loc5, loc6, loc7: integer;
  2654.     begin
  2655.         GetLeftParen;
  2656.         loc1 := GetVar;
  2657.         GetComma;
  2658.         loc2 := GetVar;
  2659.         GetComma;
  2660.         loc3 := GetVar;
  2661.         GetComma;
  2662.         loc4 := GetVar;
  2663.         GetComma;
  2664.         loc5 := GetVar;
  2665.         GetComma;
  2666.         loc6 := GetVar;
  2667.         GetComma;
  2668.         loc7 := GetVar;
  2669.         GetRightParen;
  2670.         if Token <> DoneT then
  2671.             with MacrosP^, info^ do begin
  2672.                     GetTime(date);
  2673.                     with date do begin
  2674.                             stack[loc1].value := year;
  2675.                             stack[loc2].value := month;
  2676.                             stack[loc3].value := day;
  2677.                             stack[loc4].value := hour;
  2678.                             stack[loc5].value := minute;
  2679.                             stack[loc6].value := second;
  2680.                             stack[loc7].value := DayOfWeek;
  2681.                         end;
  2682.                 end;
  2683.     end;
  2684.  
  2685.  
  2686.     procedure DoSetScale; {(scale:real; unit:string)}
  2687.         var
  2688.             id: integer;
  2689.             scale: extended;
  2690.             str: str255;
  2691.     begin
  2692.         GetLeftParen;
  2693.         scale := GetExpression;
  2694.         GetComma;
  2695.         str := GetString;
  2696.         GetRightParen;
  2697.         if token <> DoneT then
  2698.             with info^ do begin
  2699.                     if str = '' then begin
  2700.                             SetScale; {Display Set Scale dialog box}
  2701.                             exit(DoSetScale);
  2702.                         end;
  2703.                     if scale < 0.0 then begin
  2704.                             MacroError('Scale<0');
  2705.                             exit(DoSetScale);
  2706.                         end;
  2707.                     MakeLowerCase(str);
  2708.                     xUnit := str;
  2709.                     xSpatialScale := scale;
  2710.                     ySpatialScale := scale;
  2711.                     PixelAspectRatio := 1.0;
  2712.                     SpatiallyCalibrated := (xUnit <> '') and (xUnit <> 'pixel') and (xUnit <> 'pixels') and (xSpatialScale <> 0.0);
  2713.                     UpdateTitleBar;
  2714.                 end;
  2715.     end;
  2716.  
  2717.  
  2718.     procedure SaveState;
  2719.     begin
  2720.         SaveForeground := ForegroundIndex;
  2721.         SaveBackground := BackgroundIndex;
  2722.         SavePicWidth := NewPicWidth;
  2723.         SavePicHeight := NewPicHeight;
  2724.         SaveMethod := rsMethod;
  2725.         SaveCreate := rsCreateNewWindow;
  2726.         SaveAngle := rsAngle;
  2727.         SaveH := rsHScale;
  2728.         SaveV := rsVScale;
  2729.         SaveInvertY := InvertYCoordinates;
  2730.         SaveScaleArithmetic := ScaleArithmetic;
  2731.         SaveScaleConvolutions := ScaleConvolutions;
  2732.     end;
  2733.  
  2734.  
  2735.     procedure RestoreState;
  2736.     begin
  2737.         if SaveForeground = -1 then
  2738.             MacroError('State not saved')
  2739.         else begin
  2740.                 SetForegroundColor(SaveForeground);
  2741.                 SetBackgroundColor(SaveBackground);
  2742.                 NewPicWidth := SavePicWidth;
  2743.                 NewPicHeight := SavePicHeight;
  2744.                 rsMethod := SaveMethod;
  2745.                 rsCreateNewWindow := SaveCreate;
  2746.                 rsAngle := SaveAngle;
  2747.                 rsHScale := SaveH;
  2748.                 rsVScale := SaveV;
  2749.                 InvertYCoordinates := SaveInvertY;
  2750.                 ScaleArithmetic := SaveScaleArithmetic;
  2751.                 ScaleConvolutions := SaveScaleConvolutions;
  2752.             end;
  2753.     end;
  2754.  
  2755.  
  2756.     procedure DoPrint;
  2757.     begin
  2758.         FindWhatToPrint;
  2759.         if WhatToPrint <> NothingToPrint then
  2760.             Print(false)
  2761.         else
  2762.             MacroError('NothingToPrint');
  2763.     end;
  2764.  
  2765.  
  2766.     procedure SetCounter; {(n:integer)}
  2767.         var
  2768.             N, i: LongInt;
  2769.     begin
  2770.         GetLeftParen;
  2771.         N := GetInteger;
  2772.         GetRightParen;
  2773.         if (N < 0) or (N > MaxMeasurements) then
  2774.             MacroError('Argument out of range');
  2775.         if Token <> DoneT then begin
  2776.                 if N = 0 then
  2777.                     ResetCounter;
  2778.                 for i := mCount + 1 to N do
  2779.                     ClearResults(i);
  2780.                 mCount := N;
  2781.                 UpdateList;
  2782.                 ShowInfo;
  2783.             end;
  2784.     end;
  2785.  
  2786.  
  2787.     procedure OutputText;
  2788.         var
  2789.             NewLine: boolean;
  2790.             str: str255;
  2791.             i: integer;
  2792.             SaveCommand: CommandType;
  2793.     begin
  2794.         NewLine := MacroCommand <> WriteC;
  2795.         SaveCommand := MacroCommand;
  2796.         GetArguments(str);
  2797.         if token <> DoneT then begin
  2798.                 if SaveCommand = ShowMsgC then begin
  2799.                         for i := 1 to length(str) do
  2800.                             if str[i] = '\' then
  2801.                                 str[i] := cr;
  2802.                         InfoMessage := str;
  2803.                         ShowInfo;
  2804.                     end
  2805.                 else begin
  2806.                         if CurrentWindow = TextKind then
  2807.                             InsertText(str, NewLine)
  2808.                         else
  2809.                             DoDrawText(str, NewLine);
  2810.                     end;
  2811.             end;
  2812.     end;
  2813.  
  2814.  
  2815.     procedure SetErosionDilationCount; {(n:integer)}
  2816.         var
  2817.             n: LongInt;
  2818.     begin
  2819.         GetLeftParen;
  2820.         n := GetInteger;
  2821.         GetRightParen;
  2822.         if (n < 1) or (n > 8) then
  2823.             MacroError('Argument out of range');
  2824.         if Token <> DoneT then begin
  2825.                 BinaryCount := n;
  2826.                 BinaryThreshold := BinaryCount * 255;
  2827.             end;
  2828.     end;
  2829.  
  2830.  
  2831.     procedure SetSliceSpacing; {(n:real)}
  2832.         var
  2833.             n: real; {pixels}
  2834.     begin
  2835.         GetLeftParen;
  2836.         n := GetExpression;
  2837.         GetRightParen;
  2838.         if (n <= 0.0) or (n > 100.0) then
  2839.             MacroError('Argument out of range');
  2840.         if info^.StackInfo = nil then
  2841.             MacroError('No stack');
  2842.         if Token <> DoneT then
  2843.             info^.StackInfo^.SliceSpacing := n;
  2844.     end;
  2845.  
  2846.  
  2847.     procedure GetOrPutLineOrColumn;  {(x,y,count:integer:integer)}
  2848.         var
  2849.             x, y, count, i: integer;
  2850.             MaskRect: rect;
  2851.             aLine2: LineType;
  2852.     begin
  2853.         GetLeftParen;
  2854.         x := GetInteger;
  2855.         GetComma;
  2856.         y := GetInteger;
  2857.         GetComma;
  2858.         count := GetInteger;
  2859.         GetRightParen;
  2860.         if (Token <> DoneT) and (count <= MaxLine) then
  2861.             with MacrosP^ do begin
  2862.                     KillRoi;
  2863.                     case MacroCommand of
  2864.                         GetRowC: 
  2865.                             GetLine(x, y, count, aLine);
  2866.                         PutRowC:  begin
  2867.                                 PutLine(x, y, count, aLine);
  2868.                                 SetRect(MaskRect, x, y, x + count, y + 1);
  2869.                                 UpdateScreen(MaskRect);
  2870.                                 info^.changes := true;
  2871.                             end;
  2872.                         GetColumnC: 
  2873.                             GetColumn(x, y, count, aLine);
  2874.                         PutColumnC:  begin
  2875.                                 PutColumn(x, y, count, aLine);
  2876.                                 SetRect(MaskRect, x, y, x + 1, y + count);
  2877.                                 UpdateScreen(MaskRect);
  2878.                                 info^.changes := true;
  2879.                             end;
  2880.                     end; {case}
  2881.                 end;
  2882.     end;
  2883.  
  2884.  
  2885.     procedure CheckVersion; {(RequiredVersion:real)}
  2886.         var
  2887.             RequiredVersion: real;
  2888.             str: str255;
  2889.     begin
  2890.         GetLeftParen;
  2891.         RequiredVersion := GetExpression;
  2892.         GetRightParen;
  2893.         if (Token <> DoneT) then
  2894.             if round(RequiredVersion * 100.0) > version then begin
  2895.                     RealToString(RequiredVersion, 1, 2, str);
  2896.                     PutMessage(concat('This macro requires version ', str, ' or later of NIH Image.'));
  2897.                     Token := DoneT;
  2898.                 end;
  2899.     end;
  2900.  
  2901.  
  2902.     procedure SetOptions; {(Options:string)}
  2903.         var
  2904.             options: str255;
  2905.             mtype: MeasurementTypes;
  2906.             i, LastOption: integer;
  2907.             SaveMeasurements: set of MeasurementTypes;
  2908.     begin
  2909.         GetLeftParen;
  2910.         Options := GetString;
  2911.         GetRightParen;
  2912.         if (Token <> DoneT) then begin
  2913.                 SaveMeasurements := measurements;
  2914.                 MakeLowerCase(options);
  2915.                 Measurements := [];
  2916.                 if pos('area', options) <> 0 then
  2917.                     Measurements := Measurements + [AreaM];
  2918.                 if pos('mean', options) <> 0 then
  2919.                     Measurements := Measurements + [MeanM];
  2920.                 if pos('st', options) <> 0 then
  2921.                     Measurements := Measurements + [StdDevM];
  2922.                 if pos('center', options) <> 0 then
  2923.                     Measurements := Measurements + [xyLocM];
  2924.                 if pos('mode', options) <> 0 then
  2925.                     Measurements := Measurements + [ModeM];
  2926.                 if (pos('per', options) <> 0) or (pos('length', options) <> 0) then
  2927.                     Measurements := Measurements + [LengthM];
  2928.                 if pos('major', options) <> 0 then
  2929.                     Measurements := Measurements + [MajorAxisM];
  2930.                 if pos('minor', options) <> 0 then
  2931.                     Measurements := Measurements + [MinorAxisM];
  2932.                 if pos('angle', options) <> 0 then
  2933.                     Measurements := Measurements + [AngleM];
  2934.                 if pos('int', options) <> 0 then
  2935.                     Measurements := Measurements + [IntDenM];
  2936.                 if pos('max', options) <> 0 then
  2937.                     Measurements := Measurements + [MinMaxM];
  2938.                 if pos('1', options) <> 0 then
  2939.                     Measurements := Measurements + [User1M];
  2940.                 if pos('2', options) <> 0 then
  2941.                     Measurements := Measurements + [User2M];
  2942.                 UpdateFitEllipse;
  2943.                 if Measurements <> SaveMeasurements then
  2944.                     UpdateList;
  2945.             end;
  2946.     end;
  2947.  
  2948.  
  2949.     procedure SetLabel;
  2950.         var
  2951.             SaveCommand: CommandType;
  2952.             str, SaveLabel: str255;
  2953.     begin
  2954.         SaveCommand := MacroCommand;
  2955.         GetArguments(str);
  2956.         case SaveCommand of
  2957.             SetMajorC:  begin
  2958.                     SaveLabel := MajorLabel;
  2959.                     MajorLabel := str;
  2960.                     Measurements := Measurements + [MajorAxisM];
  2961.                 end;
  2962.             SetMinorC:  begin
  2963.                     SaveLabel := MinorLabel;
  2964.                     MinorLabel := str;
  2965.                     Measurements := Measurements + [MinorAxisM];
  2966.                 end;
  2967.             SetUser1C:  begin
  2968.                     SaveLabel := User1Label;
  2969.                     User1Label := str;
  2970.                     Measurements := Measurements + [User1M];
  2971.                 end;
  2972.             SetUser2C:  begin
  2973.                     SaveLabel := User2Label;
  2974.                     User2Label := str;
  2975.                     Measurements := Measurements + [User2M];
  2976.                 end;
  2977.         end; {case}
  2978.         ShowInfo;
  2979.         if str <> SaveLabel then
  2980.             UpdateList;
  2981.     end;
  2982.  
  2983.  
  2984.     procedure DoUpdateLUT;
  2985.     begin
  2986.         with info^ do begin
  2987.                 LoadLUT(ctable);
  2988.                 IdentityFunction := false;
  2989.                 if isGrayScaleLUT then
  2990.                     LutMode := CustomGrayScale
  2991.                 else begin
  2992.                         SetupPseudocolor;
  2993.                         LutMode := PseudoColor;
  2994.                     end;
  2995.                 UpdateMap;
  2996.             end;
  2997.     end;
  2998.  
  2999.  
  3000.     procedure SubtractBackground; {(Options:string; BallRadius:integer)}
  3001.         var
  3002.             options: str255;
  3003.             radius, item: integer;
  3004.     begin
  3005.         GetLeftParen;
  3006.         Options := GetString;
  3007.         GetComma;
  3008.         radius := GetInteger;
  3009.         GetRightParen;
  3010.         if (Token <> DoneT) then begin
  3011.                 MakeLowerCase(options);
  3012.                 FasterBackgroundSubtraction := pos('faster', options) <> 0;
  3013.                 item := Sub2DItem;
  3014.                 if pos('hor', options) <> 0 then
  3015.                     item := HorizontalItem;
  3016.                 if pos('ver', options) <> 0 then
  3017.                     item := VerticalItem;
  3018.                 if pos('roll', options) <> 0 then
  3019.                     item := Sub2DItem;
  3020.                 if pos('remove', options) <> 0 then
  3021.                     item := RemoveStreaksItem;
  3022.             end;
  3023.         BallRadius := Radius;
  3024.         if Radius < 1 then
  3025.             BallRadius := 1;
  3026.         if Radius > 319 then
  3027.             BallRadius := 319;
  3028.         DoBackgroundMenuEvent(Item);
  3029.     end;
  3030.  
  3031.  
  3032.     procedure SetExportMode;
  3033.         var
  3034.             mode: str255;
  3035.     begin
  3036.         mode := GetStringArg;
  3037.         if Token <> DoneT then begin
  3038.                 MakeLowerCase(mode);
  3039.                 ExportAsWhat := AsRaw;
  3040.                 if pos('mcid', mode) <> 0 then
  3041.                     ExportAsWhat := asMCID;
  3042.                 if pos('text', mode) <> 0 then
  3043.                     ExportAsWhat := asText;
  3044.                 if pos('lut', mode) <> 0 then
  3045.                     ExportAsWhat := asLUT;
  3046.                 if pos('meas', mode) <> 0 then
  3047.                     ExportAsWhat := asMeasurements;
  3048.                 if pos('plot', mode) <> 0 then
  3049.                     ExportAsWhat := asPlotValues;
  3050.                 if pos('hist', mode) <> 0 then
  3051.                     ExportAsWhat := asHistogramValues;
  3052.                 if pos('xy', mode) <> 0 then
  3053.                     ExportAsWhat := asCoordinates;
  3054.             end;
  3055.     end;
  3056.  
  3057.  
  3058.     procedure MoveCurrentWindow;{(x,y:integer)}
  3059.         var
  3060.             x, y: integer;
  3061.             ignore: integer;
  3062.             fwptr: WindowPtr;
  3063.             kind: integer;
  3064.     begin
  3065.         GetLeftParen;
  3066.         x := GetInteger;
  3067.         GetComma;
  3068.         y := GetInteger;
  3069.         GetRightParen;
  3070.         fwptr := FrontWindow;
  3071.         if fwptr <> nil then begin
  3072.                 kind := WindowPeek(fwptr)^.WindowKind;
  3073.                 if (kind = PicKind) or (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) or (kind = HistoKind) or (Kind = PasteControlKind) or (Kind = ResultsKind) or (Kind = TextKind) then
  3074.                     MoveWindow(fwptr, x, y, true);
  3075.             end;
  3076.     end;
  3077.  
  3078.  
  3079.     procedure DoUserCode; {str:str255; Param1,Param2,Param3:real;}
  3080.   {Contributed by Mark Vivino}
  3081.         var
  3082.             WhichCode: integer;
  3083.             Param1, Param2, Param3: extended;
  3084.             str: str255;
  3085.             NewVersion: boolean;
  3086.     begin
  3087.         GetLeftParen;
  3088.         GetToken;
  3089.         NewVersion := (token = StringLiteral) or (token = StringVariable);
  3090.         PutTokenBack;
  3091.         WhichCode := 0;
  3092.         str := '';
  3093.         if NewVersion then
  3094.             str := GetString
  3095.         else
  3096.             WhichCode := GetInteger;
  3097.         GetComma;
  3098.         Param1 := GetExpression;
  3099.         GetComma;
  3100.         Param2 := GetExpression;
  3101.         GetComma;
  3102.         Param3 := GetExpression;
  3103.         GetRightParen;
  3104.         if Token <> DoneT then begin
  3105.                 if NewVersion then
  3106.                     UserMacroCode(str, Param1, Param2, Param3)
  3107.                 else begin
  3108.                         if (WhichCode < 1) or (WhichCode > 10) then
  3109.                             MacroError('Range error . Allowable range is 1 to 10.');
  3110.                         OldUserMacroCode(WhichCode, Param1, Param2, Param3);
  3111.                     end;
  3112.             end;
  3113.     end;
  3114.  
  3115.  
  3116.     procedure CloseSerialPorts;
  3117.         var
  3118.             err: OSErr;
  3119.     begin
  3120.         if SerialBufferP <> nil then begin
  3121.                 err := CloseDriver(SerialOut);
  3122.                 err := CloseDriver(SerialIn);
  3123.                 DisposePtr(SerialBufferP);
  3124.             end;
  3125.     end;
  3126.  
  3127.  
  3128.     procedure OpenSerial;
  3129.         const
  3130.             SerialBufferSize = 1024;
  3131.         var
  3132.             err: OSErr;
  3133.             baud, data, stop, parity: integer;
  3134.             config: integer;
  3135.             flags: SerShk;
  3136.             str: str255;
  3137.     begin
  3138.         CloseSerialPorts;
  3139.         baud := baud9600;
  3140.         data := data8;
  3141.         stop := stop10;
  3142.         parity := noParity;
  3143.         str := GetStringArg;
  3144.         if token = DoneT then
  3145.             exit(OpenSerial);
  3146.         MakeLowerCase(str);
  3147.         if pos('300', str) <> 0 then
  3148.             baud := baud300;
  3149.         if pos('1200', str) <> 0 then
  3150.             baud := baud1200;
  3151.         if pos('2400', str) <> 0 then
  3152.             baud := baud2400;
  3153.         if pos('19200', str) <> 0 then
  3154.             baud := baud19200;
  3155.         if pos('two', str) <> 0 then
  3156.             stop := stop20;
  3157.         if pos('odd', str) <> 0 then
  3158.             parity := oddParity;
  3159.         if pos('even', str) <> 0 then
  3160.             parity := evenParity;
  3161.         if pos('seven', str) <> 0 then
  3162.             data := data7;
  3163.         if (OpenDriver('.AOut', SerialOut) <> NoErr) or (OpenDriver('.AIn', SerialIn) <> NoErr) then begin
  3164.                 MacroError('Error opening modem port');
  3165.                 exit(OpenSerial);
  3166.             end;
  3167.         SerialBufferP := NewPtr(SerialBufferSize);
  3168.         if SerialBufferP = nil then begin
  3169.                 MacroError('Out of Memory');
  3170.                 exit(OpenSerial);
  3171.             end;
  3172.         with flags do begin
  3173.                 fXOn := ord(false); {Disable xon/xoff output flow control}
  3174.                 fCTS := ord(false); {Disable CTS (output) flow control}
  3175.                 xOn := chr(17);
  3176.                 xOff := chr(19);
  3177.                 errs := 0;
  3178.                 evts := 0;
  3179.                 fInX := ord(true);  {Enable xon/xoff input flow control}
  3180.                 fDTR := ord(true); {Enable DTR (input) flow control}
  3181.             end;
  3182.         Config := baud + data + stop + parity;
  3183.         Err := SerHShake(SerialOut, flags);
  3184.         Err := SerSetBuf(SerialIn, SerialBufferP, SerialBufferSize);
  3185.         Err := SerReset(SerialOut, Config);
  3186.     end;
  3187.  
  3188.  
  3189.     procedure PutSerial;
  3190.         var
  3191.             i: integer;
  3192.             Size: LongInt;
  3193.             OutputBuffer: packed array[1..256] of char;
  3194.             str: str255;
  3195.             err: OSErr;
  3196.     begin
  3197.         GetArguments(str);
  3198.         if token = DoneT then
  3199.             exit(PutSerial);
  3200.         if SerialBufferP = nil then begin
  3201.                 MacroError('Serial port not open');
  3202.                 exit(PutSerial);
  3203.             end;
  3204.         Size := 0;
  3205.         for i := 1 to length(str) do begin
  3206.                 size := size + 1;
  3207.                 OutputBuffer[size] := str[i];
  3208.             end;
  3209.         if size > 0 then
  3210.             err := fswrite(SerialOut, size, @OutputBuffer);
  3211.     end;
  3212.  
  3213.  
  3214.     procedure DoSetCursor; {str: string}
  3215.         var
  3216.             str: str255;
  3217.     begin
  3218.         str := GetStringArg;
  3219.         if Token <> DoneT then begin
  3220.                 MakeLowerCase(str);
  3221.                 if pos('watch', str) <> 0 then
  3222.                     SetCursor(watch);
  3223.                 if pos('cross', str) <> 0 then
  3224.                     SetCursor(ToolCursor[SelectionTool]);
  3225.                 if pos('arrow', str) <> 0 then
  3226.                     InitCursor;
  3227.             end;
  3228.     end;
  3229.  
  3230.  
  3231.     procedure SetVideoOptions; {options: string}
  3232.         var
  3233.             options: str255;
  3234.             NewSyncMode: SyncModeType;
  3235.  
  3236.         procedure SetOption (id: integer; var option: boolean; enable: boolean);
  3237.     {Updates the modeless Video Control dialog box.}
  3238.         begin
  3239.             if option <> enable then
  3240.                 DoVideoControl(id)
  3241.         end;
  3242.  
  3243.     begin
  3244.         options := GetStringArg;
  3245.         if Token <> DoneT then begin
  3246.                 MakeLowerCase(options);
  3247.                 SetOption(InvertID, InvertVideo, pos('invert', options) <> 0);
  3248.                 SetOption(HighlightID, HighlightSaturatedPixels, pos('high', options) <> 0);
  3249.                 SetOption(OscillatingID, OscillatingMovies, pos('osc', options) <> 0);
  3250.                 SetOption(TriggerID, ExternalTrigger, pos('trig', options) <> 0);
  3251.                 SetOption(BlindID, BlindMovieCapture, pos('blind', options) <> 0);
  3252.                 if pos('sep', options) <> 0 then
  3253.                     NewSyncMode := SeparateSync
  3254.                 else
  3255.                     NewSyncMode := NormalSync;
  3256.                 if NewSyncMode <> SyncMode then
  3257.                     DoVideoControl(SyncID)
  3258.             end;
  3259.     end;
  3260.  
  3261.  
  3262.     procedure SetChannel; {(channel:integer)}
  3263.         var
  3264.             channel: integer;
  3265.     begin
  3266.         GetLeftParen;
  3267.         channel := GetInteger;
  3268.         GetRightParen;
  3269.         if (channel < 1) or (channel > 4) then
  3270.             MacroError('Bad channel number')
  3271.         else
  3272.             DoVideoControl(FirstChannelID + channel - 1);
  3273.     end;
  3274.  
  3275.  
  3276.     procedure DoAcquire;
  3277.         var
  3278.             fname: str255;
  3279.     begin
  3280.         fname := GetStringArg;
  3281.         LoadAcqPlugIn(fname);
  3282.     end;
  3283.  
  3284.  
  3285.     procedure DoFilter;
  3286.         var
  3287.             fname: str255;
  3288.     begin
  3289.         fname := GetStringArg;
  3290.         LoadFilterPlugIn(fname);
  3291.     end;
  3292.  
  3293.  
  3294.     procedure DoPhotoMode;
  3295.         var
  3296.             erase: boolean;
  3297.     begin
  3298.         erase := GetBooleanArg;
  3299.         if Token <> DoneT then begin
  3300.                 if erase then begin
  3301.                         EraseScreen;
  3302.                         UpdatePicWindow;
  3303.                         InPhotoMode := true;
  3304.                     end
  3305.                 else if InPhotoMode then begin
  3306.                         RestoreScreen;
  3307.                         InitCursor;
  3308.                     end;
  3309.             end;
  3310.     end;
  3311.  
  3312.  
  3313.     procedure RGBToIndexed; {options: string}
  3314.         var
  3315.             options: str255;
  3316.     begin
  3317.         options := GetStringArg;
  3318.         if Token <> DoneT then begin
  3319.                 MakeLowerCase(options);
  3320.                 RGBLut := CustomLUT;
  3321.                 DitherColor := false;
  3322.                 if pos('exist', options) <> 0 then
  3323.                     RGBLut := ExistingLUT;
  3324.                 if pos('system', options) <> 0 then
  3325.                     RGBLut := SystemLUT;
  3326.                 if pos('dither', options) <> 0 then
  3327.                     DitherColor := true;
  3328.                 ConvertRGBToEightBitColor(false);
  3329.             end;
  3330.     end;
  3331.  
  3332.  
  3333.     procedure DoAverageFrames; {[(Options:string; nFrames:integer)]}
  3334.         var
  3335.             options: str255;
  3336.             nFrames: integer;
  3337.             HasArguments: boolean;
  3338.     begin
  3339.         GetToken;
  3340.         HasArguments := token = LeftParen;
  3341.         PutTokenBack;
  3342.         if HasArguments then begin
  3343.                 GetLeftParen;
  3344.                 Options := GetString;
  3345.                 GetComma;
  3346.                 nFrames := GetInteger;
  3347.                 if nFrames > 0 then
  3348.                     FramesToAverage := nFrames;
  3349.                 GetRightParen;
  3350.                 if (Token <> DoneT) then begin
  3351.                         MakeLowerCase(options);
  3352.                         VideoRateAveraging := false;
  3353.                         SumFrames := false;
  3354.                         if (pos('int', options) <> 0) or (pos('sum', options) <> 0) then
  3355.                             sumFrames := true;
  3356.                         if pos('video', options) <> 0 then
  3357.                             VideoRateAveraging := true;
  3358.                     end;
  3359.             end; {has arguments}
  3360.         if token <> DoneT then
  3361.             AverageFrames;
  3362.     end;
  3363.  
  3364.  
  3365.     procedure DoSelectWindow;{('str')}
  3366.         var
  3367.             str, wTitle: str255;
  3368.             WPeek, NextWPeek: WindowPeek;
  3369.             id: integer;
  3370.             TempInfo: InfoPtr;
  3371.     begin
  3372.         GetArguments(str);
  3373.         MakeLowerCase(str);
  3374.         if Token <> DoneT then begin
  3375.                 wPeek := WindowPeek(FrontWindow);
  3376.                 while wPeek <> nil do begin
  3377.                         NextWPeek := wPeek^.NextWindow;
  3378.                         if wPeek^.WindowKind = PicKind then begin
  3379.                                 TempInfo := InfoPtr(wPeek^.RefCon);
  3380.                                 wTitle := TempInfo^.title;
  3381.                             end
  3382.                         else
  3383.                             wTitle := wPeek^.TitleHandle^^;
  3384.                         MakeLowerCase(wTitle);
  3385.                         if str = wTitle then begin
  3386.                                 if wPeek^.WindowKind = PicKind then begin
  3387.                                         info := InfoPtr(wPeek^.RefCon);
  3388.                                         with info^ do
  3389.                                             if (PicNum >= 1) and (PicNum <= nPics) then
  3390.                                                 SelectImage(PicNum);
  3391.                                     end
  3392.                                 else
  3393.                                     SelectWindow(WindowPtr(wPeek));
  3394.                                 leave;
  3395.                             end;
  3396.                         wpeek := NextWPeek;
  3397.                     end;
  3398.                 if wPeek = nil then
  3399.                     MacroError('Window not found');
  3400.             end;
  3401.     end;
  3402.  
  3403.  
  3404.     procedure GetThreshold;  {(lower,upper)}
  3405.         var
  3406.             loc1, loc2: integer;
  3407.     begin
  3408.         GetLeftParen;
  3409.         loc1 := GetVar;
  3410.         GetComma;
  3411.         loc2 := GetVar;
  3412.         GetRightParen;
  3413.         if Token <> DoneT then
  3414.             with MacrosP^ do
  3415.                 with info^ do begin
  3416.                         if Thresholding then begin
  3417.                                 stack[loc1].value := ColorStart;
  3418.                                 stack[loc2].value := 255;
  3419.                             end
  3420.                         else if DensitySlicing then begin
  3421.                                 stack[loc1].value := SliceStart;
  3422.                                 stack[loc2].value := SliceEnd;
  3423.                             end
  3424.                         else begin
  3425.                                 stack[loc1].value := 0;
  3426.                                 stack[loc2].value := 0;
  3427.                             end;
  3428.                     end;
  3429.     end;
  3430.  
  3431.  
  3432.     procedure SortPalette;
  3433.         type
  3434.             MyHSVColor = record
  3435.                     lHue, lSaturation, lValue: LongInt;
  3436.                 end;
  3437.             HSVRec = record
  3438.                     index: integer;
  3439.                     hsv: MyHSVColor;
  3440.                 end;
  3441.             HSVArrayType = array[0..255] of HSVRec;
  3442.         var
  3443.             TempTable: MyCSpecArray;
  3444.             i: integer;
  3445.             HSVArray: HSVArrayType;
  3446.             h, s, v: LongInt;
  3447.             fHue, fSaturation, fValue: fixed;
  3448.             TempHSV: HSVColor;
  3449.             table: LookupTable;
  3450.  
  3451.         procedure SortByHue;
  3452.     {Selection sorts from "Algorithms" by Robert Sedgewick.}
  3453.             var
  3454.                 i, j, min: integer;
  3455.                 t: HSVRec;
  3456.         begin
  3457.             for i := 1 to 254 do begin
  3458.                     min := i;
  3459.                     for j := i + 1 to 254 do
  3460.                         if HSVArray[j].hsv.lHue < HSVArray[min].hsv.lHue then
  3461.                             min := j;
  3462.                     t := HSVArray[min];
  3463.                     HSVArray[min] := HSVArray[i];
  3464.                     HSVArray[i] := t;
  3465.                 end;
  3466.         end;
  3467.  
  3468.     begin
  3469.         ShowWatch;
  3470.         DisableDensitySlice;
  3471.         with info^ do begin
  3472.                 for i := 1 to 254 do begin
  3473.                         HSVArray[i].index := i;
  3474.                         rgb2hsv(cTable[i].rgb, TempHSV);
  3475.                         with TempHSV do begin
  3476.                                 fHue := SmallFract2Fix(hue);
  3477.                                 fSaturation := SmallFract2Fix(saturation);
  3478.                                 fValue := SmallFract2Fix(value);
  3479.                             end;
  3480.                         with HSVArray[i].hsv do begin
  3481.                                 lHue := LongInt(band(fHue, $ffff));
  3482.                                 lSaturation := LongInt(band(fSaturation, $ffff));
  3483.                                 lValue := LongInt(band(fValue, $ffff));
  3484.                             end;
  3485.                     end;
  3486.                 SortByHue;
  3487.                 for i := 1 to 254 do
  3488.                     TempTable[i].rgb := cTable[HSVArray[i].index].rgb;
  3489.                 cTable := TempTable;
  3490.                 LoadLUT(cTable);
  3491.                 if info <> NoInfo then begin
  3492.                         table[0] := 0;
  3493.                         table[255] := 255;
  3494.                         for i := 1 to 254 do
  3495.                             table[HSVArray[i].index] := i;
  3496.                         ApplyTable(table);
  3497.                     end;
  3498.                 WhatToUndo := NothingToUndo;
  3499.                 SetupPseudocolor;
  3500.                 ColorTable := CustomTable;
  3501.             end; {with}
  3502.     end;
  3503.  
  3504.  
  3505.     procedure DoProject;
  3506.     begin
  3507.         if not (ProjectC in RoutinesCalled) then begin
  3508.                 if ShowProjectDialogBox then
  3509.                     DoProjection
  3510.                 else
  3511.                     token := DoneT;
  3512.             end
  3513.         else
  3514.             DoProjection;
  3515.         RoutinesCalled := RoutinesCalled + [ProjectC];
  3516.     end;
  3517.  
  3518.  
  3519.     procedure DoNewTextWindow; {(name,width,height)}
  3520.         var
  3521.             str: str255;
  3522.             okay, OptionalArguments: boolean;
  3523.             width, height: LongInt;
  3524.     begin
  3525.         GetLeftParen;
  3526.         str := GetString;
  3527.         GetToken;
  3528.         OptionalArguments := token <> RightParen;
  3529.         PutTokenBack;
  3530.         width := 500;
  3531.         height := 400;
  3532.         if OptionalArguments then begin
  3533.                 GetComma;
  3534.                 width := GetInteger;
  3535.                 if width < 8 then
  3536.                     width := 8;
  3537.                 GetComma;
  3538.                 height := GetInteger;
  3539.                 if height < 8 then
  3540.                     height := 8;
  3541.             end;
  3542.         GetRightParen;
  3543.         if Token <> DoneT then
  3544.             okay := MakeNewTextWindow(str, width, height);
  3545.     end;
  3546.  
  3547.  
  3548.     procedure ImageMath; {('op',pic1,pic2,gain,offset,'result')}
  3549.         var
  3550.             op, result: str255;
  3551.             pic1, pic2, offset: LongInt;
  3552.             gain: real;
  3553.     begin
  3554.         GetLeftParen;
  3555.         op := GetString;
  3556.         GetComma;
  3557.         pic1 := GetInteger;
  3558.         GetComma;
  3559.         pic2 := GetInteger;
  3560.         GetComma;
  3561.         gain := GetExpression;
  3562.         GetComma;
  3563.         offset := GetInteger;
  3564.         GetComma;
  3565.         result := GetString;
  3566.         GetRightParen;
  3567.         if token <> DoneT then begin
  3568.                 MakeLowerCase(op);
  3569.                 if pos('add', op) <> 0 then
  3570.                     CurrentMathOp := AddMath;
  3571.                 if pos('sub', op) <> 0 then
  3572.                     CurrentMathOp := SubMath;
  3573.                 if pos('mul', op) <> 0 then
  3574.                     CurrentMathOp := MulMath;
  3575.                 if pos('div', op) <> 0 then
  3576.                     CurrentMathOp := DivMath;
  3577.                 if pos('and', op) <> 0 then
  3578.                     CurrentMathOp := AndMath;
  3579.                 if pos('or', op) <> 0 then
  3580.                     CurrentMathOp := OrMath;
  3581.                 if pos('xor', op) <> 0 then
  3582.                     CurrentMathOp := XorMath;
  3583.                 if pos('max', op) <> 0 then
  3584.                     CurrentMathOp := MaxMath;
  3585.                 if pos('min', op) <> 0 then
  3586.                     CurrentMathOp := MinMath;
  3587.                 if pos('copy', op) <> 0 then
  3588.                     CurrentMathOp := CopyMath;
  3589.                 MathGain := gain;
  3590.                 MathOffset := offset;
  3591.                 DoMath(pic1, pic2, result);
  3592.             end;
  3593.     end;
  3594.  
  3595.  
  3596.     procedure PasteLive;
  3597.     begin
  3598.         with info^ do begin
  3599.                 if not RoiShowing or (RoiType <> RectRoi) then begin
  3600.                         MacroError('No selection');
  3601.                         exit(PasteLive);
  3602.                     end;
  3603.                 if PictureType = FrameGrabberType then begin
  3604.                         MacroError('Can''t paste into Camera window');
  3605.                         exit(PasteLive);
  3606.                     end;
  3607.                 if FrameGrabber = NoFrameGrabber then begin
  3608.                         MacroError('No frame grabber');
  3609.                         exit(PasteLive);
  3610.                     end;
  3611.                 if (RoiRect.right > fgwidth) or (RoiRect.bottom > fgheight) then begin
  3612.                         MacroError('Selection out of range');
  3613.                         exit(PasteLive);
  3614.                     end;
  3615.                 SetupUndo;
  3616.                 WhatToUndo := UndoPaste;
  3617.                 ClipBufInfo^.RoiRect := RoiRect;
  3618.                 OpPending := true;
  3619.                 CurrentOp := PasteOp;
  3620.                 LivePasteMode := true;
  3621.                 WhatsOnClip := LivePic;
  3622.             end;{with}
  3623.     end;
  3624.  
  3625.  
  3626.     procedure GetPlotData;  {(var nValues,PixelsPerValue, Min,Max:real)}
  3627.         var
  3628.             loc1, loc2, loc3, loc4: integer;
  3629.     begin
  3630.         GetLeftParen;
  3631.         loc1 := GetVar;
  3632.         GetComma;
  3633.         loc2 := GetVar;
  3634.         GetComma;
  3635.         loc3 := GetVar;
  3636.         GetComma;
  3637.         loc4 := GetVar;
  3638.         GetRightParen;
  3639.         if Token <> DoneT then
  3640.             with MacrosP^, results do begin
  3641.                     ShowPlot := false;
  3642.                     PlotDensityProfile;
  3643.                     ShowPlot := true;
  3644.                     stack[loc1].value := PlotCount;
  3645.                     stack[loc2].value := PlotAvg;
  3646.                     stack[loc3].value := ActualPlotMin;
  3647.                     stack[loc4].value := ActualPlotMax;
  3648.                 end;
  3649.     end;
  3650.  
  3651.  
  3652.     function GetStringVar: integer;
  3653.     begin
  3654.         GetStringVar := 0;
  3655.         GetToken;
  3656.         if token <> StringVariable then
  3657.             MacroError('String variable expected')
  3658.         else
  3659.             GetStringVar := TokenStackLoc;
  3660.     end;
  3661.  
  3662.  
  3663.     procedure DoDelete;  {(var dest; index, count:integer)}
  3664.         var
  3665.             StackLoc, index, count: integer;
  3666.             str: str255;
  3667.     begin
  3668.         GetLeftParen;
  3669.         StackLoc := GetStringVar;
  3670.         str := TokenStr;
  3671.         GetComma;
  3672.         index := GetInteger;
  3673.         GetComma;
  3674.         count := GetInteger;
  3675.         GetRightParen;
  3676.         if Token <> DoneT then
  3677.             with MacrosP^.stack[StackLoc] do begin
  3678.                     delete(str, index, count);
  3679.                     if StringH <> nil then
  3680.                         StringH^^ := str;
  3681.                 end;
  3682.     end;
  3683.  
  3684.  
  3685.     procedure GetScale;  {(var scale:real; unit:string)}
  3686.         var
  3687.             loc1, loc2, index, count: integer;
  3688.             str: str255;
  3689.     begin
  3690.         GetLeftParen;
  3691.         loc1 := GetVar;
  3692.         GetComma;
  3693.         loc2 := GetStringVar;
  3694.         GetRightParen;
  3695.         if Token <> DoneT then
  3696.             with info^, MacrosP^ do
  3697.                 if SpatiallyCalibrated then begin
  3698.                         stack[loc1].value := xSpatialScale;
  3699.                         stack[loc2].StringH^^ := xUnit;
  3700.                     end
  3701.                 else begin
  3702.                         stack[loc1].value := 1.0;
  3703.                         stack[loc2].StringH^^ := 'pixel';
  3704.                     end;
  3705.     end;
  3706.  
  3707.  
  3708.     procedure DoAutoOutline;  {(x,y:integer)}
  3709.         var
  3710.             x, y: integer;
  3711.             start: point;
  3712.     begin
  3713.         GetLeftParen;
  3714.         x := GetInteger;
  3715.         GetComma;
  3716.         y := GetInteger;
  3717.         GetRightParen;
  3718.         if Token <> DoneT then begin
  3719.                 start.h := x;
  3720.                 start.v := y;
  3721.                 AutoOutline(start);
  3722.             end;
  3723.     end;
  3724.  
  3725.  
  3726.     procedure ExecuteCommand;
  3727.         var
  3728.             AutoSelectAll: boolean;
  3729.             t: FateTable;  {Needed for MakeSkeleton}
  3730.             okay: boolean;
  3731.             theEvent: EventRecord;
  3732.     begin
  3733.         if Info = NoInfo then
  3734.             if not (MacroCommand in LegalWithoutImage) then begin
  3735.                     MacroError('No image window active');
  3736.                     exit(ExecuteCommand);
  3737.                 end;
  3738.         if DoOption then begin
  3739.                 OptionKeyWasDown := true;
  3740.                 DoOption := false;
  3741.             end;
  3742.         if OpPending then
  3743.             if not (MacroCommand in [CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC, SetOptionC, PasteLiveC, GetRoiC, RequiresC]) then begin
  3744.                     KillRoi; {Terminate any pending paste operation.}
  3745.                     RestoreRoi;
  3746.                 end;
  3747.         MacroOpPending := false;
  3748.         case MacroCommand of
  3749.             RotateRC, RotateLC: 
  3750.                 DoRotate(MacroCommand);
  3751.             FlipVC: 
  3752.                 FlipOrRotate(FlipVertical);
  3753.             FlipHC: 
  3754.                 FlipOrRotate(FlipHorizontal);
  3755.             CopyC:  begin
  3756.                     FindWhatToCopy;
  3757.                     if WhatToCopy = NothingToCopy then
  3758.                         MacroError('Copy failed')
  3759.                     else
  3760.                         DoCopy;
  3761.                 end;
  3762.             SelectC:  begin
  3763.                     StopDigitizing;
  3764.                     SelectAll(true);
  3765.                 end;
  3766.             PasteC: 
  3767.                 DoPaste;
  3768.             ClearC, FillC, InvertC, FrameC: 
  3769.                 with info^ do begin
  3770.                         AutoSelectAll := not RoiShowing;
  3771.                         if AutoSelectAll then
  3772.                             SelectAll(true);
  3773.                         case MacroCommand of
  3774.                             ClearC: 
  3775.                                 DoOperation(EraseOp);
  3776.                             FillC: 
  3777.                                 DoOperation(PaintOp);
  3778.                             InvertC: 
  3779.                                 DoOperation(InvertOp);
  3780.                             FrameC: 
  3781.                                 DoOperation(FrameOp);
  3782.                         end;
  3783.                         UpdateScreen(RoiRect);
  3784.                         if AutoSelectAll then
  3785.                             KillRoi
  3786.                         else
  3787.                             MacroOpPending := true;
  3788.                     end;
  3789.             KillC: 
  3790.                 KillRoi;
  3791.             RestoreC: 
  3792.                 if NoInfo^.RoiType <> NoRoi then
  3793.                     RestoreRoi;
  3794.             AnalyzeC: 
  3795.                 AnalyzeParticles;
  3796.             ConvolveC: 
  3797.                 DoConvolve;
  3798.             NextC: 
  3799.                 GetNextWindow;
  3800.             MarkC: 
  3801.                 MarkSelection(mCount);
  3802.             MeasureC:  begin
  3803.                     Measure;
  3804.                     InitCursor;
  3805.                 end;
  3806.             MakeBinC: 
  3807.                 MakeBinary;
  3808.             DitherC: 
  3809.                 Filter(Dither, 0, t);
  3810.             SmoothC: 
  3811.                 if OptionKeyWasDown then
  3812.                     Filter(UnweightedAvg, 0, t)
  3813.                 else
  3814.                     Filter(WeightedAvg, 0, t);
  3815.             SharpenC: 
  3816.                 Filter(fsharpen, 0, t);
  3817.             ShadowC: 
  3818.                 Filter(fshadow, 0, t);
  3819.             TraceC: 
  3820.                 Filter(EdgeDetect, 0, t);
  3821.             ReduceC: 
  3822.                 Filter(ReduceNoise, 0, t);
  3823.             RedirectC: 
  3824.                 RedirectSampling := GetBooleanArg;
  3825.             ThresholdC: 
  3826.                 SetThreshold;
  3827.             AutoThresholdC: 
  3828.                 AutoThreshold;
  3829.             ResetgmC: 
  3830.                 ResetGrayMap;
  3831.             WaitC: 
  3832.                 DoWait;
  3833.             ResetmC: 
  3834.                 ResetCounter;
  3835.             SetSliceC: 
  3836.                 SetDensitySlice;
  3837.             UndoC: 
  3838.                 DoUndo;
  3839.             SetForeC, SetBackC: 
  3840.                 SetColor;
  3841.             HistoC:  begin
  3842.                     DoHistogram;
  3843.                     DrawHistogram;
  3844.                 end;
  3845.             EnhanceC: 
  3846.                 EnhanceContrast;
  3847.             EqualizeC: 
  3848.                 EqualizeHistogram;
  3849.             ErodeC:  begin
  3850.                     BinaryIterations := 1;
  3851.                     DoErosion;
  3852.                 end;
  3853.             DilateC:  begin
  3854.                     BinaryIterations := 1;
  3855.                     DoDilation;
  3856.                 end;
  3857.             OutlineC: 
  3858.                 filter(OutlineFilter, 0, t);
  3859.             ThinC: 
  3860.                 MakeSkeleton;
  3861.             AddConstC, MulConstC: 
  3862.                 DoConstantArithmetic;
  3863.             RevertC: 
  3864.                 DoRevert;
  3865.             BeepC: 
  3866.                 Beep;
  3867.             NopC: 
  3868.                 ;
  3869.             MakeC, MakeOvalC: 
  3870.                 MakeRoi;
  3871.             MoveC: 
  3872.                 MoveRoi;
  3873.             InsetC: 
  3874.                 InsetRoi;
  3875.             MoveToC: 
  3876.                 DoMoveTo;
  3877.             DrawTextC, WriteC, WritelnC, ShowMsgC: 
  3878.                 OutputText;
  3879.             SetFontC: 
  3880.                 SetFont;
  3881.             SetFontSizeC: 
  3882.                 SetFontSize;
  3883.             SetTextC: 
  3884.                 SetText;
  3885.             DrawNumC: 
  3886.                 DrawNumber;
  3887.             ExitC: 
  3888.                 token := DoneT;
  3889.             GetPicSizeC: 
  3890.                 GetPicSize;
  3891.             PutMsgC: 
  3892.                 DoPutMessage;
  3893.             GetRoiC: 
  3894.                 GetRoi;
  3895.             MakeNewC: 
  3896.                 DoMakeNewWindow;
  3897.             DrawScaleC: 
  3898.                 if info^.RoiShowing then begin
  3899.                         DrawScale;
  3900.                         UpdatePicWindow
  3901.                     end
  3902.                 else
  3903.                     MacroError('No Selection');
  3904.             SetPaletteC: 
  3905.                 DoSetPalette;
  3906.             OpenC, ImportC: 
  3907.                 DoOpenImage;
  3908.             SetImportC: 
  3909.                 SetImportAttributes;
  3910.             SetMinMaxC: 
  3911.                 SetImportMinMax;
  3912.             SetCustomC: 
  3913.                 SetCustomImport;
  3914.             SelectPicC, ChoosePicC: 
  3915.                 SelectPic;
  3916.             SetPicNameC: 
  3917.                 SetPicName;
  3918.             ApplyLutC: 
  3919.                 ApplyLookupTable;
  3920.             SetSizeC: 
  3921.                 SetNewSize;
  3922.             SaveC: 
  3923.                 DoSave;
  3924.             SaveAllC: 
  3925.                 SaveAll;
  3926.             SaveAsC: 
  3927.                 DoSaveAs;
  3928.             CopyResultsC: 
  3929.                 DoCopyResults;
  3930.             CloseC, DisposeC: 
  3931.                 CloseWindow;
  3932.             DisposeAllC: 
  3933.                 DisposeAll;
  3934.             DupC: 
  3935.                 DoDuplicate;
  3936.             GetInfoC: 
  3937.                 GetInfo;
  3938.             PrintC: 
  3939.                 DoPrint;
  3940.             LineToC: 
  3941.                 DoLineTo;
  3942.             GetLineC: 
  3943.                 DoGetLine;
  3944.             ShowPasteC: 
  3945.                 if PasteControl = nil then
  3946.                     ShowPasteControl
  3947.                 else
  3948.                     BringToFront(PasteControl);
  3949.             ChannelC: 
  3950.                 SetChannel;
  3951.             ColumnC, PlotProfileC:  begin
  3952.                     PlotDensityProfile;
  3953.                     if PlotWindow <> nil then
  3954.                         UpdatePlotWindow;
  3955.                 end;
  3956.             ScaleC, ScaleSelectionC: 
  3957.                 DoScaleAndRotate;
  3958.             SetOptionC: 
  3959.                 DoOption := true;
  3960.             SetLabelsC: 
  3961.                 DrawPlotLabels := GetBooleanArg;
  3962.             SetPlotScaleC: 
  3963.                 SetPlotScale;
  3964.             SetDimC: 
  3965.                 SetPlotDimensions;
  3966.             GetResultsC: 
  3967.                 GetResults;
  3968.             CopyModeC, AndC, OrC, XorC, BlendC, ReplaceC, AddC, SubC, MulC, DivC: 
  3969.                 DoPasteOperation;
  3970.             ScaleMathC: 
  3971.                 ScaleArithmetic := GetBooleanArg;
  3972.             InvertYC: 
  3973.                 InvertYCoordinates := GetBooleanArg;
  3974.             SetWidthC: 
  3975.                 SetWidth;
  3976.             ShowResultsC:  begin
  3977.                     ShowResults;
  3978.                     UpdateList
  3979.                 end;
  3980.             StartC: 
  3981.                 StartDigitizing;
  3982.             StopC: 
  3983.                 StopDigitizing;
  3984.             CaptureC: 
  3985.                 CaptureOneFrame;
  3986.             GetRowC, PutRowC, GetColumnC, PutColumnC: 
  3987.                 GetOrPutLineOrColumn;
  3988.             PlotXYZC: 
  3989.                 PlotXYZ;
  3990.             IncludeC: 
  3991.                 IncludeHoles := GetBooleanArg;
  3992.             AutoC: 
  3993.                 WandAutoMeasure := GetBooleanArg;
  3994.             LabelC: 
  3995.                 LabelParticles := GetBooleanArg;
  3996.             OutlineParticlesC: 
  3997.                 OutlineParticles := GetBooleanArg;
  3998.             IgnoreC: 
  3999.                 IgnoreParticlesTouchingEdge := GetBooleanArg;
  4000.             AdjustC: 
  4001.                 WandAdjustAreas := GetBooleanArg;
  4002.             SetParticleSizeC: 
  4003.                 SetParticleSize;
  4004.             SetPrecisionC: 
  4005.                 SetPrecision;
  4006.             PutPixelC: 
  4007.                 DoPutPixel;
  4008.             ScalingOptionsC: 
  4009.                 SetScaling;
  4010.             SetExportC: 
  4011.                 SetExportMode;
  4012.             ExportC: 
  4013.                 DoExport;
  4014.             ChangeC: 
  4015.                 DoChangeValues;
  4016.             UpdateResultsC:  begin
  4017.                     ShowInfo;
  4018.                     DeleteLines(mCount, mCount);
  4019.                     AppendResults;
  4020.                 end;
  4021.             CascadeC: 
  4022.                 CascadeImages;
  4023.             SetMajorC, SetMinorC, SetUser1C, SetUser2C: 
  4024.                 SetLabel;
  4025.             GetMouseC: 
  4026.                 DoGetMouse;
  4027.             SelectSliceC, ChooseSliceC, AddSliceC, DeleteSliceC, ResliceC:  begin
  4028.                     if info^.StackInfo = nil then
  4029.                         MacroError('No stack');
  4030.                     if token <> DoneT then
  4031.                         case MacroCommand of
  4032.                             SelectSliceC, ChooseSliceC: 
  4033.                                 DoSelectSlice;
  4034.                             AddSliceC: 
  4035.                                 okay := AddSlice(true);
  4036.                             DeleteSliceC: 
  4037.                                 DeleteSlice;
  4038.                             ResliceC: 
  4039.                                 Reslice;
  4040.                         end;
  4041.                 end;
  4042.             MakeStackC: 
  4043.                 MakeNewStack;
  4044.             AverageFramesC: 
  4045.                 DoAverageFrames;
  4046.             TriggerC: 
  4047.                 WaitForTrigger;
  4048.             MakeLineC: 
  4049.                 MakeLineRoi;
  4050.             GetTimeC: 
  4051.                 DoGetTime;
  4052.             SetScaleC: 
  4053.                 DoSetScale;
  4054.             SaveStateC: 
  4055.                 SaveState;
  4056.             RestoreStateC: 
  4057.                 RestoreState;
  4058.             SetCounterC: 
  4059.                 SetCounter;
  4060.             UpdateLutC: 
  4061.                 DoUpdateLUT;
  4062.             SetCountC: 
  4063.                 SetErosionDilationCount;
  4064.             PropagateLutC: 
  4065.                 DoPropagate(1);
  4066.             PropagateSpatialC: 
  4067.                 DoPropagate(2);
  4068.             PropagateDensityC: 
  4069.                 DoPropagate(3);
  4070.             SetSpacingC: 
  4071.                 SetSliceSpacing;
  4072.             RequiresC: 
  4073.                 CheckVersion;
  4074.             SetOptionsC: 
  4075.                 SetOptions;
  4076.             SubtractBackgroundC: 
  4077.                 SubtractBackground;
  4078.             MoveWindowC: 
  4079.                 MoveCurrentWindow;
  4080.             UserCodeC: 
  4081.                 DoUserCode;
  4082.             InvertLutC:  begin
  4083.                     InvertPalette;
  4084.                     UpdateLUT;
  4085.                 end;
  4086.             OpenSerialC: 
  4087.                 OpenSerial;
  4088.             PutSerialC: 
  4089.                 PutSerial;
  4090.             SetCursorC: 
  4091.                 DoSetCursor;
  4092.             SetVideoC: 
  4093.                 SetVideoOptions;
  4094.             AcquireC: 
  4095.                 DoAcquire;
  4096.             FilterC: 
  4097.                 DoFilter;
  4098.             PhotoModeC: 
  4099.                 DoPhotoMode;
  4100.             RGBToIndexedC: 
  4101.                 RGBToIndexed;
  4102.             SurfacePlotC: 
  4103.                 PlotSurface;
  4104.             SelectWindowC: 
  4105.                 DoSelectWindow;
  4106.             NewTextWindowC: 
  4107.                 DoNewTextWindow;
  4108.             CaptureColorC: 
  4109.                 CaptureColor;
  4110.             GetThresholdC: 
  4111.                 GetThreshold;
  4112.             AverageSlicesC: 
  4113.                 AverageSlices;
  4114.             SortPaletteC: 
  4115.                 SortPalette;
  4116.             ProjectC: 
  4117.                 DoProject;
  4118.             ScaleConvolutionsC: 
  4119.                 ScaleConvolutions := GetBooleanArg;
  4120.             ImageMathC: 
  4121.                 ImageMath;
  4122.             PasteLiveC: 
  4123.                 PasteLive;
  4124.             GetPlotDataC: 
  4125.                 GetPlotData;
  4126.             DeleteC: 
  4127.                 DoDelete;
  4128.             GetScaleC: 
  4129.                 GetScale;
  4130.             AutoOutlineC: 
  4131.                 DoAutoOutline;
  4132.         end; {case}
  4133.         OptionKeyWasDown := false;
  4134.         if not macro then begin
  4135.                 Token := DoneT;
  4136.                 KillRoi;
  4137.             end;
  4138.         if TickCount > MacroTicks then begin
  4139.                 MacroTicks := TickCount + 10;
  4140.                 if EventAvail(everyEvent, theEvent) then
  4141.                     ; {Allows background tasks to run}
  4142.                 if CommandPeriod then begin
  4143.                         Token := DoneT;
  4144.                         KillRoi;
  4145.                     end;
  4146.             end;
  4147.     end;
  4148.  
  4149.  
  4150.     procedure DoCompoundStatement;
  4151.     begin
  4152.         if token <> BeginT then
  4153.             MacroError('"begin" expected');
  4154.         GetToken;
  4155.         while (token <> endT) and (token <> DoneT) do begin
  4156.                 DoStatement;
  4157.                 GetToken;
  4158.                 if Token = SemiColon then
  4159.                     GetToken
  4160.                 else if token <> EndT then
  4161.                     MacroError(EndExpected);
  4162.             end;
  4163.     end;
  4164.  
  4165.  
  4166.     procedure SkipCompoundStatement;
  4167.         var
  4168.             count: integer;
  4169.     begin
  4170.         count := 1;
  4171.         repeat
  4172.             GetToken;
  4173.             case token of
  4174.                 beginT: 
  4175.                     count := count + 1;
  4176.                 endT: 
  4177.                     count := count - 1;
  4178.                 DoneT:  begin
  4179.                         MacroError('"end" expected');
  4180.                         exit(SkipCompoundStatement);
  4181.                     end;
  4182.                 otherwise
  4183.             end; {case}
  4184.         until count = 0;
  4185.     end;
  4186.  
  4187.  
  4188.     procedure DoDeclarations;
  4189.     begin
  4190.         if token = SemiColon then
  4191.             GetToken;
  4192.         if token = VarT then begin
  4193.                 GetToken;
  4194.                 while ((token = Identifier) or (token = variable) or (token = StringVariable)) and (Token <> DoneT) do
  4195.                     DoDeclaration;
  4196.             end;
  4197.     end;
  4198.  
  4199.  
  4200.     procedure DoFor;
  4201.         var
  4202.             SavePC, StackLoc: integer;
  4203.             StartValue, EndValue, i: LongInt;
  4204.     begin
  4205.         StackLoc := GetVar;
  4206.         GetToken;
  4207.         if token <> AssignOp then begin
  4208.                 MacroError('":=" expected');
  4209.                 exit(DoFor);
  4210.             end;
  4211.         StartValue := GetInteger;
  4212.         if token = DoneT then
  4213.             exit(DoFor);
  4214.         GetToken;
  4215.         if token <> ToT then begin
  4216.                 MacroError('"to" expected');
  4217.                 exit(DoFor);
  4218.             end;
  4219.         EndValue := GetInteger;
  4220.         if token = DoneT then
  4221.             exit(DoFor);
  4222.         GetToken;
  4223.         if token <> DoT then begin
  4224.                 MacroError(DoExpected);
  4225.                 exit(DoFor);
  4226.             end;
  4227.         SavePC := pc;
  4228.         if StartValue > EndValue then begin
  4229.                 GetToken;
  4230.                 SkipStatement
  4231.             end
  4232.         else
  4233.             for i := StartValue to EndValue do
  4234.                 with MacrosP^ do begin
  4235.                         Stack[StackLoc].value := i;
  4236.                         pc := SavePC;
  4237.                         GetToken;
  4238.                         DoStatement;
  4239.                         if CommandPeriod then
  4240.                             token := DoneT;
  4241.                         if Token = DoneT then
  4242.                             leave;
  4243.                         if Digitizing then
  4244.                             DoCapture;
  4245.                     end;
  4246.     end;
  4247.  
  4248.  
  4249.     procedure SkipFor;
  4250.     begin
  4251.         GetToken;
  4252.         SkipPartialStatement;
  4253.         GetToken;
  4254.         if token <> doT then
  4255.             MacroError(DoExpected);
  4256.         GetToken;
  4257.         SkipStatement
  4258.     end;
  4259.  
  4260.  
  4261.     procedure DoAssignment;
  4262.         var
  4263.             SaveStackLoc: integer;
  4264.     begin
  4265.         SaveStackLoc := TokenStackLoc;
  4266.         GetToken;
  4267.         if token <> AssignOp then begin
  4268.                 MacroError('":=" expected');
  4269.                 exit(DoAssignment);
  4270.             end;
  4271.         MacrosP^.stack[SaveStackLoc].value := GetExpression;
  4272.     end;
  4273.  
  4274.  
  4275.     procedure DoStringAssignment;
  4276.         var
  4277.             SaveStackLoc: integer;
  4278.             str: Str255;
  4279.     begin
  4280.         SaveStackLoc := TokenStackLoc;
  4281.         GetToken;
  4282.         if token <> AssignOp then begin
  4283.                 MacroError('":=" expected');
  4284.                 exit(DoStringAssignment);
  4285.             end;
  4286.         str := GetString;
  4287.         if token <> DoneT then
  4288.             with MacrosP^.stack[SaveStackLoc] do
  4289.                 if StringH <> nil then
  4290.                     StringH^^ := str;
  4291.     end;
  4292.  
  4293.  
  4294.     procedure SkipPartialStatement;
  4295.         var
  4296.             done: Boolean;
  4297.     begin
  4298.         done := token = DoneT;
  4299.         while not done do begin
  4300.                 case token of
  4301.                     ThenT, DoT, SemiColon, EndT, ElseT, UntilT:  begin
  4302.                             PutTokenBack;
  4303.                             done := true;
  4304.                         end;
  4305.                     DoneT, BeginT, ForT, IfT, WhileT, RepeatT:  begin
  4306.                             MacroError('end of statement expected');
  4307.                             done := true;
  4308.                         end;
  4309.                     otherwise
  4310.                         GetToken;
  4311.                 end;
  4312.             end;
  4313.     end;
  4314.  
  4315.  
  4316.     procedure DoIf;
  4317.         var
  4318.             isTrue: boolean;
  4319.     begin
  4320.         isTrue := GetBoolean;
  4321.         GetToken;
  4322.         if token <> ThenT then
  4323.             MacroError(ThenExpected);
  4324.         if isTrue then begin
  4325.                 GetToken;
  4326.                 DoStatement
  4327.             end
  4328.         else begin
  4329.                 GetToken;
  4330.                 SkipStatement;
  4331.             end;
  4332.         GetToken;
  4333.         if token = elseT then begin
  4334.                 if isTrue then begin
  4335.                         GetToken;
  4336.                         SkipStatement
  4337.                     end
  4338.                 else begin
  4339.                         GetToken;
  4340.                         DoStatement;
  4341.                     end;
  4342.             end
  4343.         else
  4344.             PutTokenBack;
  4345.     end;
  4346.  
  4347.  
  4348.     procedure SkipIf;
  4349.     begin
  4350.         GetToken;
  4351.         SkipPartialStatement;
  4352.         GetToken;
  4353.         if token <> thenT then
  4354.             MacroError(ThenExpected);
  4355.         GetToken;
  4356.         SkipStatement;
  4357.         GetToken;
  4358.         if token <> elseT then
  4359.             PutTokenBack
  4360.         else begin
  4361.                 GetToken;
  4362.                 SkipStatement
  4363.             end
  4364.     end;
  4365.  
  4366.  
  4367.     procedure DoWhile;
  4368.         var
  4369.             isTrue: boolean;
  4370.             SavePC: integer;
  4371.     begin
  4372.         SavePC := pc;
  4373.         repeat
  4374.             pc := SavePC;
  4375.             isTrue := GetBoolean;
  4376.             GetToken;
  4377.             if token <> doT then
  4378.                 MacroError(DoExpected);
  4379.             if isTrue then begin
  4380.                     GetToken;
  4381.                     DoStatement
  4382.                 end
  4383.             else begin
  4384.                     GetToken;
  4385.                     SkipStatement;
  4386.                 end;
  4387.             if Digitizing then
  4388.                 DoCapture;
  4389.             if CommandPeriod then
  4390.                 token := DoneT;
  4391.         until not isTrue or (Token = DoneT);
  4392.     end;
  4393.  
  4394.  
  4395.     procedure SkipWhile;
  4396.     begin
  4397.         GetToken;
  4398.         SkipPartialStatement;
  4399.         GetToken;
  4400.         if token <> doT then
  4401.             MacroError(DoExpected);
  4402.         GetToken;
  4403.         SkipStatement
  4404.     end;
  4405.  
  4406.  
  4407.     procedure DoRepeat;
  4408.         var
  4409.             isTrue: boolean;
  4410.             SavePC: integer;
  4411.     begin
  4412.         SavePC := pc;
  4413.         isTrue := true;
  4414.         repeat
  4415.             pc := SavePC;
  4416.             GetToken;
  4417.             while (token <> untilT) and (token <> DoneT) do begin
  4418.                     DoStatement;
  4419.                     GetToken;
  4420.                     if Token = SemiColon then
  4421.                         GetToken;
  4422.                     if CommandPeriod then
  4423.                         token := DoneT;
  4424.                 end;
  4425.             if token <> untilT then
  4426.                 MacroError(UntilExpected);
  4427.             isTrue := GetBoolean;
  4428.             if Digitizing then
  4429.                 DoCapture;
  4430.         until isTrue or (Token = DoneT);
  4431.     end;
  4432.  
  4433.  
  4434.     procedure SkipRepeat;
  4435.     begin
  4436.         GetToken;
  4437.         while (token <> untilT) and (token <> DoneT) do begin
  4438.                 SkipStatement;
  4439.                 GetToken;
  4440.                 if token = SemiColon then
  4441.                     GetToken
  4442.                 else if token <> UntilT then
  4443.                     MacroError(UntilExpected);
  4444.             end;
  4445.         GetToken;
  4446.         SkipPartialStatement;
  4447.     end;
  4448.  
  4449.  
  4450.     procedure DoArrayAssignment;
  4451.         var
  4452.             SaveCommand: CommandType;
  4453.             index, LutValue, PixelValue, RegisterValue: LongInt;
  4454.             SyncChannel: integer;
  4455.     begin
  4456.         SaveCommand := MacroCommand;
  4457.         GetToken;
  4458.         if token <> LeftBracket then
  4459.             MacroError('"[" expected');
  4460.         Index := GetInteger;
  4461.         GetToken;
  4462.         if token <> RightBracket then
  4463.             MacroError('"]" expected');
  4464.         GetToken;
  4465.         if token <> AssignOp then
  4466.             MacroError('":=" expected');
  4467.  
  4468.         if SaveCommand = BufferC then begin
  4469.                 CheckIndex(index, 0, MaxLine - 1);
  4470.                 PixelValue := GetInteger;
  4471.                 RangeCheck(PixelValue);
  4472.                 if token <> DoneT then
  4473.                     MacrosP^.aLine[index] := PixelValue;
  4474.                 exit(DoArrayAssignment);
  4475.             end;
  4476.  
  4477.         if SaveCommand in [RedLutC, BlueLutC, GreenLutC] then begin
  4478.                 CheckIndex(index, 0, 255);
  4479.                 LutValue := GetInteger;
  4480.                 RangeCheck(LutValue);
  4481.                 if token <> DoneT then
  4482.                     with info^.cTable[index].rgb do
  4483.                         case SaveCommand of
  4484.                             RedLutC: 
  4485.                                 red := bsl(LutValue, 8);
  4486.                             GreenLutC: 
  4487.                                 green := bsl(LutValue, 8);
  4488.                             BlueLutC: 
  4489.                                 blue := bsl(LutValue, 8);
  4490.                         end;
  4491.                 exit(DoArrayAssignment);
  4492.             end;
  4493.  
  4494.         if SaveCommand = ScionC then begin
  4495.                 if framegrabber <> ScionLG3 then
  4496.                     MacroError('No Scion LG-3');
  4497.                 if Token <> DoneT then
  4498.                     CheckIndex(index, 1, 4);
  4499.                 if Token = DoneT then
  4500.                     exit(DoArrayAssignment);
  4501.                 if index = 3 then
  4502.                     MacroError('DataIn is read-only');
  4503.                 RegisterValue := GetInteger;
  4504.                 if token <> DoneT then begin
  4505.                         if RegisterValue < 0 then
  4506.                             RegisterValue := 0;
  4507.                         if RegisterValue > 255 then
  4508.                             RegisterValue := 255;
  4509.                         case index of
  4510.                             1:  begin
  4511.                                     LG3DacA := RegisterValue;
  4512.                                     DacAReg^ := LG3DacA
  4513.                                 end;
  4514.                             2:  begin
  4515.                                     LG3DacB := RegisterValue;
  4516.                                     DacBReg^ := LG3DacB
  4517.                                 end;
  4518.                             4:  begin
  4519.                                     LG3DataOut := band(RegisterValue, $f);
  4520.                                     if SyncMode = SeparateSync then
  4521.                                         SyncChannel := 3
  4522.                                     else
  4523.                                         SyncChannel := VideoChannel;
  4524.                                     ChannelReg^ := bor(LG3DataOut, bor(bsl(VideoChannel, 4), bsl(SyncChannel, 6)));
  4525.                                 end;
  4526.                         end; {case}
  4527.                     end;
  4528.                 exit(DoArrayAssignment);
  4529.             end;
  4530.  
  4531.         if SaveCommand = PlotDataC then begin
  4532.                 CheckIndex(index, 0, MaxLine - 1);
  4533.                 PlotData^[index] := GetExpression;
  4534.                 exit(DoArrayAssignment);
  4535.             end;
  4536.  
  4537.         CheckIndex(index, 1, MaxMeasurements);
  4538.         if token <> DoneT then
  4539.             case SaveCommand of
  4540.                 rAreaC: 
  4541.                     mArea^[Index] := GetExpression;
  4542.                 rMeanC: 
  4543.                     mean^[Index] := GetExpression;
  4544.                 rStdDevC: 
  4545.                     sd^[Index] := GetExpression;
  4546.                 rXC: 
  4547.                     xcenter^[Index] := GetExpression;
  4548.                 rYC: 
  4549.                     ycenter^[Index] := GetExpression;
  4550.                 rLengthC: 
  4551.                     plength^[Index] := GetExpression;
  4552.                 rMinC: 
  4553.                     mMin^[Index] := GetExpression;
  4554.                 rMaxC: 
  4555.                     mMax^[Index] := GetExpression;
  4556.                 rMajorC: 
  4557.                     MajorAxis^[Index] := GetExpression;
  4558.                 rMinorC: 
  4559.                     MinorAxis^[Index] := GetExpression;
  4560.                 rAngleC: 
  4561.                     orientation^[Index] := GetExpression;
  4562.                 rUser1C: 
  4563.                     User1^[Index] := GetExpression;
  4564.                 rUser2C: 
  4565.                     User2^[Index] := GetExpression;
  4566.                 otherwise
  4567.                     MacroError('Read-only array');
  4568.             end; {case}
  4569.     end;
  4570.  
  4571.  
  4572.     procedure PushArguments (var nArgs: integer);
  4573.         var
  4574.             arg: array[1..MaxArgs] of extended;
  4575.             StringArg: array[1..MaxArgs] of boolean;
  4576.             i, nStringArgs: integer;
  4577.             TempName: SymbolType;
  4578.     begin
  4579.         nArgs := 0;
  4580.         nStringArgs := 0;
  4581.         GetToken;
  4582.         while token in [Variable, StringVariable, StringLiteral, NumericLiteral, TrueT, FalseT, FunctionT, StringFunctionT, comma, MinusOp, LeftParen] do begin
  4583.                 if token = comma then
  4584.                     GetToken;
  4585.                 if nArgs < MaxArgs then
  4586.                     nArgs := nArgs + 1
  4587.                 else
  4588.                     MacroError('Too many arguments');
  4589.                 if (token = StringVariable) or (token = StringLiteral) or (token = StringFunctionT) then begin
  4590.                         nStringArgs := nStringArgs + 1;
  4591.                         arg[nArgs] := 0.0;
  4592.                         StringArg[nArgs] := true;
  4593.                         if token = StringFunctionT then
  4594.                             TokenStr := DoStringFunction;
  4595.                     end
  4596.                 else begin
  4597.                         PutTokenBack;
  4598.                         arg[nArgs] := GetExpression;
  4599.                         StringArg[nArgs] := false;
  4600.                     end;
  4601.                 if nStringArgs > 1 then
  4602.                     MacroError('No more than one string argument allowed');
  4603.                 GetToken;
  4604.             end;
  4605.         if token <> RightParen then
  4606.             MacroError(RightParenExpected);
  4607.         for i := 1 to nArgs do begin
  4608.                 if TopOfStack < MaxMacroStackSize then
  4609.                     TopOfStack := TopOfStack + 1
  4610.                 else
  4611.                     MacroError(StackOverflow);
  4612.                 with MacrosP^.stack[TopOfStack] do begin
  4613.                         value := arg[i];
  4614.                         StringH := nil;
  4615.                         if StringArg[i] then begin
  4616.                                 vType := StringVar;
  4617.                                 StringsAllocated := true;
  4618.                                 StringH := str255H(NewHandle(SizeOf(str255)));
  4619.                                 if StringH = nil then begin
  4620.                                         MacroError('Out of memory');
  4621.                                         Token := DoneT
  4622.                                     end
  4623.                                 else
  4624.                                     StringH^^ := TokenStr;
  4625.                             end
  4626.                         else
  4627.                             vType := RealVar;
  4628.                         value := arg[i];
  4629.                     end;
  4630.             end;
  4631.     end;
  4632.  
  4633.  
  4634.     procedure DoProcedure;
  4635.         var
  4636.             SavePC, SavePCStart, NewPCStart, SaveStackLoc, nArgs, i: integer;
  4637.             SaveProcName, NewProcName: SymbolType;
  4638.             SaveStringsAllocated: boolean;
  4639.     begin
  4640.         NewPCStart := TokenLoc;
  4641.         NewProcName := TokenSymbol;
  4642.         SaveStackLoc := TopOfStack;
  4643.         SaveStringsAllocated := StringsAllocated;
  4644.         StringsAllocated := false;
  4645.         GetToken;
  4646.         if token = LeftParen then
  4647.             PushArguments(nArgs)
  4648.         else begin
  4649.                 nArgs := 0;
  4650.                 PutTokenBack;
  4651.             end;
  4652.         SavePCStart := PCStart;
  4653.         PCStart := NewPCStart;
  4654.         LineStartPC := NewPCStart;
  4655.         SaveProcName := MacroOrProcName;
  4656.         MacroOrProcName := NewProcName;
  4657.         SavePC := pc;
  4658.         pc := pcStart;
  4659.         if nArgs > 0 then begin
  4660.                 GetLeftParen;
  4661.                 i := 0;
  4662.                 GetToken;
  4663.                 while token in [Identifier, Variable, StringVariable, comma, colon, SemiColon, RealT, IntegerT, BooleanT, StringT] do begin
  4664.                         if (token = Identifier) or (token = Variable) or (token = StringVariable) then begin
  4665.                                 if i < nArgs then
  4666.                                     i := i + 1
  4667.                                 else
  4668.                                     MacroError('Too many formal arguments');
  4669.                                 MacrosP^.stack[SaveStackLoc + i].SymbolTableIndex := SymbolTableloc;
  4670.                             end;
  4671.                         GetToken;
  4672.                     end;
  4673.                 if Token = VarT then
  4674.                     MacroError('VAR parameters not supported');
  4675.                 if i < nArgs then
  4676.                     MacroError('Too few formal arguments');
  4677.                 if token <> RightParen then
  4678.                     MacroError(RightParenExpected);
  4679.             end;
  4680.         GetToken;
  4681.         if (token = LeftParen) and (nArgs = 0) then
  4682.             MacroError('Arguments not expected');
  4683.         DoDeclarations;
  4684.         DoCompoundStatement;
  4685.         pc := SavePC;
  4686.         if StringsAllocated then
  4687.             DeallocateStrings(SaveStackLoc + 1, TopOfStack);
  4688.         StringsAllocated := SaveStringsAllocated;
  4689.         TopOfStack := SaveStackLoc;
  4690.         pcStart := SavePCStart;
  4691.         MacroOrProcName := SaveProcName;
  4692.     end;
  4693.  
  4694.  
  4695.     procedure CannotBeginWithThis;
  4696.         var
  4697.             str: str255;
  4698.     begin
  4699.         str := '';
  4700.         ConvertTokenToString(token, str);
  4701.         MacroError(concat('Statement cannot begin with ', '"', str, '"'));
  4702.     end;
  4703.  
  4704.  
  4705.     procedure DoStatement;
  4706.     begin
  4707.         case token of
  4708.             BeginT: 
  4709.                 DoCompoundStatement;
  4710.             CommandT: 
  4711.                 ExecuteCommand;
  4712.             UserCommandT: 
  4713.                 DoUserToken;
  4714.             ForT: 
  4715.                 DoFor;
  4716.             IfT: 
  4717.                 DoIf;
  4718.             WhileT: 
  4719.                 DoWhile;
  4720.             RepeatT: 
  4721.                 DoRepeat;
  4722.             Identifier: 
  4723.                 MacroError('Undefined identifier');
  4724.             Variable: 
  4725.                 DoAssignment;
  4726.             StringVariable: 
  4727.                 DoStringAssignment;
  4728.             ArrayT: 
  4729.                 DoArrayAssignment;
  4730.             ProcedureT: 
  4731.                 DoProcedure;
  4732.             ElseT: 
  4733.                 MacroError('Statement expected');
  4734.             FunctionT, StringFunctionT, UserFuncT, UserStrFuncT: 
  4735.                 MacroError('Variable expected');
  4736.             SemiColon: 
  4737.                 PutTokenBack; {Null statement}
  4738.             otherwise
  4739.                 CannotBeginWithThis
  4740.         end;
  4741.     end;
  4742.  
  4743.  
  4744.     procedure SkipStatement;
  4745.     begin
  4746.         case token of
  4747.             BeginT: 
  4748.                 SkipCompoundStatement;
  4749.             ForT: 
  4750.                 SkipFor;
  4751.             IfT: 
  4752.                 SkipIf;
  4753.             WhileT: 
  4754.                 SkipWhile;
  4755.             RepeatT: 
  4756.                 SkipRepeat;
  4757.             CommandT, Variable, StringVariable, ArrayT, ProcedureT: 
  4758.                 SkipPartialStatement;
  4759.             DoneT: 
  4760.                 ; {Aborting the macro}
  4761.             SemiColon, EndT, ElseT, UntilT: 
  4762.                 PutTokenBack; {These tokens can follow a statement}
  4763.             otherwise
  4764.                 CannotBeginWithThis
  4765.         end;
  4766.     end;
  4767.  
  4768.  
  4769.  
  4770.     procedure RunMacro (nMacro: integer);
  4771.         var
  4772.             count: integer;
  4773.             str: str255;
  4774.             SaveInfo: InfoPtr;
  4775.     begin
  4776.         DefaultFileName := '';
  4777.         str := '';
  4778.         nSaves := 0;
  4779.         DefaultRefNum := 0;
  4780.         count := 0;
  4781.         pcStart := MacroStart[nMacro];
  4782.         pc := pcStart;
  4783.         SavePC := pcStart;
  4784.         LineStartPC := pcStart;
  4785.         token := NullT;
  4786.         macro := true;
  4787.         MacroOpPending := false;
  4788.         DoOption := false;
  4789.         SaveInfo := info;
  4790.         TopOfStack := nGlobals;
  4791.         MacroOrProcName := BlankSymbol;
  4792.         StringsAllocated := false;
  4793.         InPhotoMode := false;
  4794.         RoutinesCalled := [];
  4795.         GetToken;
  4796.         DoDeclarations;
  4797.         DoCompoundStatement;
  4798.         if (info <> SaveInfo) and (info <> NoInfo) then
  4799.             SelectWindow(info^.wptr);
  4800.         with info^, RoiRect do begin
  4801.                 if ((right - left) <= 0) or ((bottom - top) <= 0) then
  4802.                     KillRoi;
  4803.             end;
  4804.         if info^.RoiShowing then begin
  4805.                 if MacroOpPending then begin
  4806.                         KillRoi;
  4807.                         RestoreRoi;
  4808.                     end
  4809.                 else
  4810.                     UpdatePicWindow;
  4811.             end;
  4812.         macro := false;
  4813.         if StringsAllocated then
  4814.             DeallocateStrings(nGlobals + 1, TopOfStack);
  4815.         if InPhotoMode then
  4816.             RestoreScreen;
  4817.     end;
  4818.  
  4819.  
  4820.     procedure RunKeyMacro (ch: char; KeyCode: integer);
  4821.         const
  4822.             FunctionKey = 16;
  4823.         var
  4824.             i: integer;
  4825.     begin
  4826.         if (ord(ch) = 0) then
  4827.             exit(RunKeyMacro);
  4828.         if (ch >= 'A') and (ch <= 'Z') then
  4829.             ch := chr(ord(ch) + 32); {Convert to lower case}
  4830.         if ord(ch) = FunctionKey then
  4831.             case KeyCode of
  4832.                 122: 
  4833.                     ch := 'A';
  4834.                 120: 
  4835.                     ch := 'B';
  4836.                 99: 
  4837.                     ch := 'C';
  4838.                 118: 
  4839.                     ch := 'D';
  4840.                 96: 
  4841.                     ch := 'E';
  4842.                 97: 
  4843.                     ch := 'F';
  4844.                 98: 
  4845.                     ch := 'G';
  4846.                 100: 
  4847.                     ch := 'H';
  4848.                 101: 
  4849.                     ch := 'I';
  4850.                 109: 
  4851.                     ch := 'J';
  4852.                 103: 
  4853.                     ch := 'K';
  4854.                 111: 
  4855.                     ch := 'L';
  4856.                 105: 
  4857.                     ch := 'M';
  4858.                 107: 
  4859.                     ch := 'N';
  4860.                 113: 
  4861.                     ch := 'O';
  4862.                 otherwise
  4863.             end;
  4864.         for i := 1 to nMacros do
  4865.             if ch = MacroKey[i] then begin
  4866.                     RunMacro(i);
  4867.                     leave;
  4868.                 end;
  4869.     end;
  4870.  
  4871.  
  4872.  
  4873. end.